From c028c83235bcf9e96c64e82c60534a234074c939 Mon Sep 17 00:00:00 2001 From: Alam Ed Arias Date: Sun, 3 Aug 2014 23:49:33 -0400 Subject: [PATCH] SRB2 2.1.9 release --- doc/manual/manual.htm | 2425 +---------------- readme.txt | 2 +- src/Makefile | 2 +- src/Makefile.cfg | 2 +- src/console.c | 7 +- src/d_clisrv.c | 82 +- src/d_clisrv.h | 7 +- src/d_main.c | 5 +- src/d_net.c | 3 +- src/d_netcmd.c | 195 +- src/d_player.h | 5 +- src/dehacked.c | 172 +- src/doomdef.h | 6 +- src/doomstat.h | 13 + src/f_finale.c | 16 +- src/g_game.c | 35 +- src/hardware/hw_main.c | 5 - src/info.c | 2 +- src/lua_baselib.c | 244 +- src/lua_hook.h | 11 + src/lua_hooklib.c | 82 + src/lua_hudlib.c | 220 +- src/lua_libs.h | 4 + src/lua_maplib.c | 600 +++- src/lua_mobjlib.c | 2 +- src/lua_playerlib.c | 21 +- src/lua_script.c | 18 + src/lua_skinlib.c | 30 +- src/m_cheat.c | 189 +- src/m_cheat.h | 5 + src/m_menu.c | 18 +- src/p_enemy.c | 42 +- src/p_floor.c | 95 +- src/p_inter.c | 225 +- src/p_local.h | 7 + src/p_map.c | 222 +- src/p_maputl.c | 340 ++- src/p_maputl.h | 3 +- src/p_mobj.c | 881 +++--- src/p_saveg.c | 28 +- src/p_setup.c | 19 +- src/p_spec.c | 688 ++--- src/p_spec.h | 1 + src/p_user.c | 1634 ++++++----- src/r_data.c | 2 +- src/r_defs.h | 3 +- src/r_main.c | 1 + src/sdl/Srb2SDL-vc10.vcxproj | 16 +- .../macosx/Srb2mac.xcodeproj/project.pbxproj | 4 +- src/sdl12/Makefile.cfg | 2 +- src/sdl12/Srb2SDL-vc10.vcxproj | 10 +- src/sdl12/Srb2SDL-vc9.vcproj | 8 +- src/sdl12/Srb2SDL.dsp | 4 +- src/sdl12/hwsym_sdl.c | 2 +- src/sdl12/i_cdmus.c | 2 +- src/sdl12/i_main.c | 2 +- src/sdl12/i_net.c | 2 +- src/sdl12/i_system.c | 2 +- src/sdl12/i_video.c | 2 +- .../macosx/Srb2mac.xcodeproj/project.pbxproj | 8 +- src/sdl12/mixer_sound.c | 2 +- src/sdl12/ogl_sdl.c | 2 +- src/sdl12/sdl_sound.c | 4 +- src/sounds.h | 1 - src/st_stuff.c | 4 +- src/v_video.c | 281 +- src/v_video.h | 7 +- 67 files changed, 4007 insertions(+), 4977 deletions(-) diff --git a/doc/manual/manual.htm b/doc/manual/manual.htm index 57e9bb0c9..bdf4d2a98 100644 --- a/doc/manual/manual.htm +++ b/doc/manual/manual.htm @@ -1,2393 +1,68 @@ - + Sonic Robo Blast 2 Manual - + + +

- title.png (43991 bytes) + SONIC +
+ ROBO BLAST 2

Manual

-

- Design and content on SRB2 is copyright 1998-2009 by Sonic Team Junior. - All non-original material in this game is copyrighted by their respective - owners, and no copyright infringement is intended. This game's staff make - no profit whatsoever (in fact, we lose money). THIS GAME - SHOULD NOT BE SOLD FOR ANY COST WHATSOEVER! Sonic Team - Junior is in no way affiliated with Sega or Sonic Team. -

-
-
-
- - - - - - - -
- Table of Contents -
-
    -
  1. System Requirements -
  2. -
  3. Items - -
  4. -
  5. Special Moves -
  6. -
  7. Basic Gameplay -
  8. -
  9. Surroundings -
  10. -
  11. Multiplayer - -
  12. -
  13. Zones -
  14. -
  15. Controls - -
  16. -
  17. Console Command Summary - -
  18. -
  19. Extras -
  20. -
  21. Troubleshooting -
  22. -
-
-
-
-
-

- thanks.png (8396 bytes)Thank you for installing SRB2! This fan - created tribute game to one of the greatest video game series has - been over 11 years in the making. Before you begin play, please note the - system requirements below to make sure you have an enjoyable experience. -

-

- - System Requirements -

-

- Minimum Spec (320x200): -

- -

- Recommended Spec (640x400): -

- -

- SRB2 will run on lesser machines, but is generally not recommended. -

-

-

-
-

- - Items -

-

- There are many items you will encounter throughout the game that Sonic - and his friends can use to their advantage. Below is a short summary of - the most common ones you will find. -

-

-

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

- Ring0000.png (1178 bytes) -

-
- Ring -

- The main lifeline for Sonic & Co. Your collection of rings - will scatter when hit, but as long as you have one, you cannot be - killed (except from a pit or crusher). -

-
- ring.png (1109 bytes) - - 10 Ring Box -

- Adds 10 rings to your cache -

-
- wshield.png (1114 bytes) - - Whirlwind Shield -

- Protects you from one hit. Press the spin button while jumping to - perform a second jump. Beware, though, as the second jump stops - you from spinning. -

-
- yshield.png (1112 bytes) - - Attraction Shield -

- Protects you from one hit. This will attract nearby rings. Don't - go too deep in the water, or you'll short it out! -

-
- bshield.png (1113 bytes) - - Force Shield -

- Protects you from two hits. It has a reflect ability that is automatically - activated when it gets hit. -

-
- gshield.png (1113 bytes) - - Elemental Shield -

- Protects you from one hit. This protects you from the elements, keeps - you from drowning, and creates a flaming trail when you spindash that - will damage your enemies! -

-
- rshield.png (1110 bytes) - - Armaggeddon Shield -

- Protects you from one hit. When you get hit, the shield will - explode, wiping out all enemies within its blast radius, - destroying the shield. The explosion can be triggered by pressing - the spin button while jumping as well. -

-
- invc.png (1112 bytes) - - Invincibility -

- Makes you invincible for 20 seconds. -

-
- shoes.png (1118 bytes) - - Super Sneakers -

- Increases your speed for 20 seconds. -

-
- soneup.png (1118 bytes)
- soneup.png (1118 bytes)
- soneup.png (1118 bytes) -
- One-Up -

- Gives you an extra life. In match and CTF, it gives you 100 rings. -

-
- mixup.png (1162 bytes) - - Teleporter Scramble -

- In multiplayer, this will scramble the positions of all players - in the game. -

-
- recycler.png (1230 bytes) - - Recycler -

- In multiplayer, this will scramble all of the players' powerups. - This includes ammo, powerups, and weapons. -

-
- eggbox.png (1157 bytes) - - Eggman -

- Harms your player. Watch out! -

-
- random.png (1105 bytes) - - Random Item -

- What's in the box? Only way to find out is to open it! -

-
- token.png (1122 bytes) - -

- Warp Token -

-

- At the end of the act, you will be taken to a special stage, - giving you the chance to snatch one of the Chaos Emeralds back - from Dr. Eggman's grasp! There are at least one of these in each - act. -

-
- emblem.png (1368 bytes) - - Emblem -

- These are hidden in every act, except ones where you have to - confront Eggman. Different ones appear depending on which - character you play as. Getting enough of these will unlock - special bonuses! You may obtain more by meeting special criteria, - such as completing the game with all of the chaos emeralds. When - you've picked up these emblems, they will disappear. If you find - them again in a new game, they will be faded, indicating that you - have already obtained that emblem. Check the statistics to see - which emblems are missing from your collection. -

-
-

- In CTF, there are team based rings and monitors. -

-

- red_ring.png (1219 bytes) - red_monitor.png (1199 bytes) - blue_ring.png (1218 bytes) - blue_monitor.png (1160 bytes) -

-
-
-
-

- -

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

- Special Multiplayer Items -

-

- In certain multiplayer games, you can use the following match weapons - to change the kind of rings you throw. Make sure you grab the weapon, - the ammo, and have rings or else it won't fire. -

-
-

- red_ring.png (1219 bytes) -

-
-

- Red Ring (Default Weapon) -

-

- This is your default weapon. It can't be dropped and it uses normal rings - for ammo. -

-
-

- wpnpanel_auto.png (1399 bytes) - RNGA0000.png (1100 bytes) -

-
-

- Automatic -

-

- Hold down the THROW key for a constant stream of rings. -

-
-

- wpnpanel_bounce.png (1533 bytes) - RNGB0000.png (1275 bytes) -

-
-

- Bounce -

-

- When fired, the bounce ring acts like a normal red ring, except that - it will bounce off walls, ceilings, and floors for a bit before disappearing. - Great for firing around corners and in small rooms. -

-
-

- wpnpanel_explosion.png (1359 bytes) - RNGE0000.png (1326 bytes) -

-
-

- Explosion -

-

- When this ring hits a wall, it scatters rings everywhere in a - fireworks-like display. Players hit directly by the black ring - get knocked back farther than normal. -

-
-

- wpnpanel_grenade.png (1455 bytes) - RNGG0000.png (1227 bytes) -

-
-

- Grenade -

-

- Fires a grenade that explodes by proximity. Great for guarding CTF - bases and for chucking in places where you expect the opponent will run. -

-
-

- wpnpanel_rail.png (1489 bytes) - RNGR0000.png (1163 bytes) -

-
-

- Rail -

-

- Snipe at your enemies with this instant-hit weapon! Players hit - with this weapon get knocked back farther than normal. -

-
-

- wpnpanel_scatter.png (1370 bytes) - RNGS0000.png (1127 bytes) -

-
-

- Scatter -

-

- Fires 5 rings that spread out as they go farther. The distance the - opponent flies when hit varies depending on how far the shot traveled - in the air. At point-blank range, scatter will send the opponent - flying across the stage, leaving their items easily taken. -

-
-

- WARNING! -

-

- metal.png (5951 bytes) -

-

- If you are hit while carrying any of these special rings, they - will be dropped. Pick them up quickly to keep your opponents from - stealing them! -

-
-
-
-
-

- - Special Moves -

-

- Sonic and his friends each have abilities unique to themselves. Below is - a summary of each character's special moves. -

-

-

-
- - - - - - - - - - -
-

- Sonic -

-
-

- airspin.png (4279 bytes) -

-
- Air Spin Attack -

- While jumping, press the jump button again to hurl Sonic forward - in a burst of speed. -

-
-
-
-
- - - - - - - - - - - - - -
-

- Tails -

-
-

- tailsfly.png (18615 bytes) -

-
- Fly -

- While jumping, press the jump button repeatedly to fly for a - short time. If you are playing with a friend, fly over them to - pick them up for a ride! -

-
- Swim -

- While underwater, press the jump button repeatedly to swim for a - short time. Just like flying, you can pick up others to give them - a lift. -

-
-
-
-
- - - - - - - - - - - - - -
-

- Knuckles -

-
-

- knuckles.png (16482 bytes) -

-
- Glide -

- While jumping, press and hold the jump button again to glide. Use - the directional keys to steer. -

-
- Climb -

- If you collide with a wall while gliding, Knuckles will latch - onto it. Use the directional keys to move along the wall. Press - the jump button to release and turn around, or press the spin - button to release while still facing the wall. -

-
-
-
-
-

- - Basic Gameplay -

-
- - - - - - - - - - - - - - - - - - - - - - - -
-

    Your main objective is to stop Eggman's plans for world - domination. The game is set over eight zones ranging from green - fields and ancient sunken cities to raging volcanoes and the Egg - Rock itself. Each zone is split up into three acts, the third one - being a battle against Dr. Eggman in one of his powerful machines.

-
-

- eggman.png (12925 bytes) -

-
-

- attack.png (3880 bytes) -

-
-

    When you encounter enemies, to defeat them, simply use your - spin attack by jumping. Enemies can also be destroyed by spinning - through them along the ground. Knuckles can even glide through his - enemies.

-
-

    However, beware! You are not invulnerable and, unless you have - at least one ring, an enemy will kill you on contact, or if you are - hit by one of their attacks. If you get hit by an enemy while you - have rings, you will survive, but your rings will be dropped and - scattered. You can pick them back up again, but only if you are - quick; rings will dissapear after a few seconds have elapsed! You - can find out how many rings you have in the top-left hand part of - the screen.

-
-

- stats_rings.png (19450 bytes) -

-
-

- wshield.png (1114 bytes) - yshield.png (1112 bytes) - bshield.png (1113 bytes) - gshield.png (1113 bytes) - rshield.png (1110 bytes) -

-
-

    You can also obtain shields, which will dissapate to protect - you if you are hit by a robot or an attack. Some shields have - additional powers, which were described above, along with other - power-ups you can obtain.

-
-

    Getting killed by a robot or by other hazards (described below) - will result in the loss of one life - keep an eye on your lives in - the bottom left hand side of the screen - losing all of your lives - will end your game (unless you have a continue)!

-
-

- stats_lives.png (19359 bytes) -

-
-
-
-
-

- - Surroundings -

-

- The following is a description of several objects or environments you - will encounter. -

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

- spring1.png (941 bytes) - spring2.png (941 bytes) - spring3.png (1071 bytes) - spring4.png (1046 bytes) -

-

- spring5.png (1107 bytes) - spring6.png (1138 bytes) - spring7.png (940 bytes) - spring8.png (940 bytes) -

-
-

- Springs -

-

- These springs will bounce you in the direction they are pointing. - There are two varieties, yellow and red. The red spring is much - stronger than the yellow spring. Beware though, as some springs - may throw you headlong into trouble! -

-
-

- platform.png (47948 bytes) -

-
-

- Floating Platforms -

-

- These platforms may move up and down, allowing you to hitch a - ride. Careful timing may be needed to leap from one platform to - the next. -

-
-

- fan.png (1089 bytes) -

-
-

- Fans -

-

- Powerful fans swirl around at a high speed and produces a power - blast of wind. It is advised to be careful on these, as it is - easy to go flying off the fans and into danger! -

-
-

- conveyor.png (59401 bytes) -

-
-

- Conveyor Belts -

-

- Found in most of Eggman's factories, these conveyor belts are - used to quickly transport robotic components and robots. While - you can also make use of them, be alert! Eggman has changed the - movements of them to lead an unwary player into a trap! -

-
-

- water.png (33687 bytes) -

-
-

- Water -

-

- All three characters can go underwater, but movement is greatly - slowed down, and only Tails can swim. Bear in mind that you - cannot breathe while you are underwater and must make use of the - air pockets that are found bubbling out of cracks in the floor. A - countdown will appear if you are dangerously close to running out - of air. If time runs out, you will drown and lose a life. -

-
-

- slime.png (67845 bytes) -

-
-

- Slime -

-

- This is largely predominant in zones where Eggman has been at - work, such as the Techno Hill Zone. You can wade in it, but don't - get in too deep! The only way to safely swim is with an elemental - shield. -

-
-

- crusher.png (49485 bytes) -

-
-

- Crushers -

-

- These traps are lethal and will immediately kill anyone trapped - under one - even invincibility will not protect you here. -

-
-

- pit.png (5508 bytes) -

-
-

- Deep Pits -

-

- Like crushers, these traps immediately take one life and - invincibility is useless. -

-
-
-
-
-

- - Multiplayer -

-

- Not only can you play SRB2 alone, but with a network connection, your - friends as well! -

-

- -

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

- coop.png (11051 bytes) -

-

- Co-Op -

-
- Similar to a single player game, you can play through the single - player levels together. Up to 32 players allowed, but a maximum of - 8 is suggested. -
-

- match.png (7565 bytes) -

-

- Match -

-
- It's a free for all, and the one with the most points wins! Run - around picking up rings to hurl at your opponent. Points are given - depending on the status of your target:
-
    -
  • Rings or Shield - 50 pts. -
  • -
  • No Rings or Shield - 100 pts. -
  • -
-

- The player with the most points at the end of the round wins the - round.
-
- Press the "Rankings" key to view scores. Up to a maximum of 32 - players allowed. -

-
-

- match.png (7565 bytes) -

-

- Team Match -

-
- It's a team based fight to the finish. Play match with teammates, - and the team with the biggest total score wins. Scoring is the same - as match mode.
-
- Press the "Rankings" key to view scores. Up to a maximum of 32 - players allowed. -
-

- race.png (5364 bytes) -

-

- Classic Race -

-
- Just like Sonic 2's split screen mode, each player must race to the - end of the level. At the end of the stage, players will be ranked - based on the following five categories:
-
    -
  • Score - The player with the most points wins this category. -
  • -
  • Time - The player who beat the stage the fastest wins this - category. -
  • -
  • Ring - The player who completed the stage with the most rings - wins this category. -
  • -
  • Total Ring - The player who picked up the most rings wins - this category. Rings lost to enemies and hazards still count - towards this score. -
  • -
  • Item Box - The player who broke the most powerup monitors - wins this category. -
  • -
-

- When one player has completed the stage, the rest of the players - in the game have 60 seconds to complete the stage or they will - die and the round will end. The player who wins the most - categories wins the round. -

-
-

- race.png (5364 bytes) -

-

- Race -

-
- Just like Sonic 3's split screen mode, each player must race to the - end of the level. When one player has completed the stage, the rest - of the players in the game have 60 seconds to complete the stage or - they will die and the round will end. Best time wins! -
-

- tag.png (11057 bytes) -

-

- Tag -

-
- You're it! Up to 32 people can play in this touch-and-run frenzy! - One player is it, and can tag others either by throwing a ring, or - by touching them. You become it once you're hit. In some levels - there is a no-tag zone, but don't stay in there too long! You gain - points by avoiding a tag each time one occurs. -

- Press the "Rankings" key to view scores. Up to a maximum of 32 - players allowed. -

-
-

- ctf.png (8251 bytes) -

-

- Capture the Flag -

-
- Just like the popular FPS game, but with a platforming twist! - Choose a team - Red or Blue. Grab the opposing team's flag and - bring it back to your base while your own team's flag is in the - base to score a point. -

- Press the "Rankings" key to view scores. Up to a maximum of 32 - players allowed. -

-
-
-
-

- You'll notice that in the LEVEL NAME, after the level, are letters in - parenthesis. This tells you what kind of level it is. -

-

- C = Cooperative/Single Player -

-

- R = Race/Classic Race -

-

- M = Match/Team Match -

-

- T = Tag -

-

- F = Capture the Flag -

-

- - Special Multiplayer Console Commands -

-

- Multiplayer can make heavy use of the console, and you may find several - commands to your advantage. Please refer to the Console Command - Summary below. -

-

- SRB2 uses ports 5029 and 5030 for network communication using the UDP - protocol. -

-
-

- - Zones
-

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

- gfz.png (19494 bytes) -

-
- GREENFLOWER ZONE -
- Sonic and friends immediately set out for the Greenflower Zone. - Luckily, you've reached this green haven before Eggman has had a - chance to completely take control. Whilst exploring this level, - keep your eyes peeled for anything hidden among the foilage... - including robots! -
-

- thz.png (23896 bytes) -

-
- TECHNO HILL ZONE -
- Once a beautiful landscape, Eggman has turned this into a - slime-ridden mess. You'll eventually reach the factory, and once - inside, you'll have to negotiate lasers and crushers that have been - installed to stop your progress. Finally, a battle will ensue on a - high speed rail cart... -
-

- dsz.png (32144 bytes) -

-
- DEEP SEA ZONE -
- Sonic, Tails and Knuckles stumble upon some ruins, which have been flooded, - partly by nature and partly by Eggman digging for the Chaos Emeralds. Be - wary of water traps which can threaten to drown you! -
-

- cez.png (36151 bytes) -

-
- CASTLE EGGMAN ZONE -
- Having retreated here, Sonic, Tails and Knuckles must launch a - full-scale assault on this castle and defeat Eggman, who is - residing in the lower levels. Not only is this castle guarded by a - huge wall, but Eggman has laid several traps inside that will catch - you off guard! -
-

- acz.png (43670 bytes) -

-
- ARID CANYON ZONE -
- Having escaped Eggman's stronghold, you come across a huge canyon. - While Sonic must find a way to cross this, Tails and Knuckles can use - their abilites to the fullest. Be careful not to enjoy the scenery too - much, as there are plenty of falling platforms and obstacles. -
-

- rvz.png (45020 bytes) -

-
- RED VOLCANO ZONE -
- Finding Eggman's robots entering the volcano, you follow them to - investigate what's happening. Rather than worrying about Eggman's - traps here, you should be more concerned with the deadly lava, that - threatens to rise without warning. -
-

- unknown.png (546 bytes) -

-
- EGG ROCK ZONE -
- You've finally arrived at the Eggrock Zone. Who knows what's in here? - Except for a few surprises, maybe. -
-

- unknown.png (546 bytes) -

-
- ??? -
- More hidden levels are waiting to be unlocked... can you find them? -
-
-
-

- -

-
-

- - Controls -

-

- The following are the default controls and their definition. You can - change the controls by going to Options/Setup Controls in the menu. Player 2's controls - can be changed as well. -

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Forward -

- Default Key: Up Or W -

-
- Moves your player forward. -
- Reverse -

- Default Key: Down Or S -

-
- Moves your player in reverse. -
- Turn Left -

- Default Key: Left -

-
- Turns your player left. -
- Turn Right -

- Default Key: Right -

-
- Turns your player right. -
- Jump -

- Default Key: Z Or Mouse2 -

-
- Makes your player jump. -
- Spin -

- Default Key: X -

-
- If standing still, this will rev a spindash. If you are moving and - on the ground, you will go into a spin. -
- Ring Toss -

- Default Key: RCTRL Or Mouse1 -

-
- If in a multiplayer game that permits it, this button throws a - ring. -
- Ring Toss Normal -

- Default Key: C -

-
- If in a multiplayer game that permits it, this button will throw a - normal ring, whether you have special weapons or not. -
- Taunt -

- Default Key: V -

-
- If in a multiplayer game, this key throws one of four random taunts - at your opponents, providing they exist for your character. Sonic, - Tails, and Knuckles do not have taunts. -
- Toss Flag -

- Default Key: ' (Apostrophe) -

-
- Press this key to throw a flag - you are carrying (Capture the Flag). -
- Strafe On -

- Default Key: RALT -

-
- Hold this down to use the Left and Right keys to strafe. -
- Strafe Left -

- Default Key: A -

-
- Makes your player sidestep to the left. -
- Strafe Right -

- Default Key: D -

-
- Makes your player sidestep to the right. -
- Look Up -

- Default Key: PageUp -

-
- Tilts the camera upward. -
- Look Down -

- Default Key: PageDown -

-
- Tilts the camera downward. -
- Center View -

- Default Key: End -

-
- Centers the camera view. -
- Mouselook -

- Default Key: --- (No default key assigned) -

-
- When held down, use the mouse to move your view. -
- Talk Key -

- Default Key: T -

-
- Talk to other players in the game. -
- Team-Talk Key -

- Default Key: Y -

-
- Talk to team members in the game. -
- Rankings/Scores -

- Default Key: Tab -

-
- View current scores/statistics. -
- Console -

- Default Key: ~ (Tilde) -

-
- Brings down the console. For advanced users only. -
- Next Weapon -

- Default Key: E -

-
- Changes your weapon to the next one. -
- Previous Weapon -

- Default Key: Q -

-
- Changes your weapon to the previous one. -
- Weapon Slot 1 -

- Default Key: 1 -

-
- Changes your weapon to slot 1. -
- Weapon Slot 2 -

- Default Key: 2 -

-
- Changes your weapon to slot 2. -
- Weapon Slot 3 -

- Default Key: 3 -

-
- Changes your weapon to slot 3. -
- Weapon Slot 4 -

- Default Key: 4 -

-
- Changes your weapon to slot 4. -
- Weapon Slot 5 -

- Default Key: 5 -

-
- Changes your weapon to slot 5. -
- Weapon Slot 6 -

- Default Key: 6 -

-
- Changes your weapon to slot 6. -
- Weapon Slot 7 -

- Default Key: 7 -

-
- Changes your weapon to slot 7. -
- Rotate Camera L -

- Default Key: ( -

-
- Rotates the camera left. -
- Rotate Camera R -

- Default Key: ) -

-
- Rotates the camera right. -
- Reset Camera -

- Default Key: R -

-
- Resets the camera if it gets stuck. -
- Pause -

- Default Key: Pause/Break -

-
- Pauses the game. -
-
-
-

- - Joystick Setup -

-
- - - - - - - - - - -
-

- controls.png (22752 bytes) -

-
- You can also use a joystick with SRB2! Look in the controls menu - for a joystick menu to set it up! -
- If you have an analog joystick/gamepad, you are welcome to try the - "Analog Control" option in the Options menu. In collaboration with - the Rotate Camera L and R buttons, you may prefer this method of - control over the standard one. Available in single player and - split-screen, but not network games. -
-
-
-

- -

-
-

- - Console Command Summary -

-

- This is a general summary of some of the console commands that are in SRB2. - More information can be found on the website. -

-

- - Commands -

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
- CONNECT <ip> - - Connects to the specified IP address. If no IP is specified, it - will search on the LAN for a game. -
- KICK <name or node #> - - Kicks a player in the current game (server only). -
- GETPLAYERNUM - - Lists all of the players in the game, their number in the array, - and their node #s. -
- SAVE <slot> <description> - - Saves your game. -
- LOAD <slot> - - Loads a saved game. -
- TUNES <slot> - - Temporarily changes the game music. -
- DISPLAYPLAYER - - Displays the number of the current player being displayed. -
- LISTSERV - - Retrieves a list of games currently running if the master list is - active. -
- NODES - - Lists all of the players in the game and their node #s. -
- SCREENSHOT - - Takes a screenshot of the game. Useful to bind a key to. -
- CHANGECONFIG <filename> - - Saves the current config and loads another. -
- LOADCONFIG <filename> - - Loads a new config without saving. -
- SAVECONFIG <filename> - - Saves the current configuration. -
- SETCONTROL -

- SETCONTROL2 -

-
- Manually changes the controls of 1P and 2P. See config.cfg for an - example. -
- CHATMACRO - - Type in HELP CHATMACRO for more information. -
- QUIT - - Exits the game. -
- PAUSE - - Pauses the game. -
- ADDFILE <filename> - - Adds a file to the game. -
- EXITLEVEL - - Exits the current level. -
- EXITGAME - - Exits the current game. -
- MAP MAPxx (01-99) - - Changes the level. -
- STOPDEMO - - Stops the currently running demo. -
- TIMEDEMO - - Plays back a demo at full speed. Useful for benchmarking. -
- PLAYDEMO - - Plays back a recorded demo. -
- CHANGETEAM x (RED or BLUE) - - Changes the current CTF team you are on. -
- BIND <key> <command> - - Binds a command to a key. -
- CLS - - Clears the console buffer. -
- TOGGLE - - Type HELP TOGGLE for more information -
- HELP - - Provides help. -
- WAIT - - Waits a certain number of game tics before executing the next - command. -
- EXEC <filename> - - Executes a console script. -
- ECHO - - Echos whatever you type. -
- ALIAS - - Creates an alias. Type HELP ALIAS for more information. -
- SAYTEAM <message> - - Sends a message to your team. -
- SAYTO <playername> <message> - - Sends a message to this player. -
- SAY <message> - - Sends a message to everyone. -
- MEMFREE - - Displays memory usage statistics. -
+ +
+ +
+ +
-
-
-

- - Variables -

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- SV_MAXPLAYERS (on/off) - - Sets the maximum number of players allowed to be in this game. -
- SV_ALLOWNEWPLAYERS (on/off) - - Allow new players to join instantly or not. Setting this to NO - forces them to wait until the next map change. -
- SURROUND (on/off) - - Toggles DirectSound3D acceleration. -
- PRECACHESOUND (on/off) - - Tells the game to precache sound or not before playing. -
- STEREOREVERSE (on/off) - - Toggles reverse stereo mode. -
- CAM_ROTSPEED <integer> -

- CAM2_ROTSPEED <integer> -

-
- Changes the rotation speed of the camera. -
- CAM_ROTATE <integer> -

- CAM2_ROTATE <integer> -

-
- Changes the angle of the camera's rotation. -
- CAM_SPEED <integer> -

- CAM2_SPEED <integer> -

-
- Changes the speed of the camera. -
- CAM_HEIGHT <integer> -

- CAM2_HEIGHT <integer> -

-
- Changes the height of the camera. -
- CAM_STILL (on/off) -

- CAM2_STILL (on/off) -

-
- Forces the camera angle to freeze in place. -
- CAM_DIST <integer> -

- CAM2_DIST <integer> -

-
- Changes the distance of the camera. -
- ALLOWMLOOK - - Allow players to mouselook in a netgame (server only) -
- SONICCD (on/off) - - An alternate mode of death for enemies. -
- CHASECAM (on/off) -

- CHASECAM2 (on/off) -

-
- Turns the camera on and off. -
- GRAVITY <decimal value> - - Changes the gravity when allowed. -
- TRANSLUCENCY (on/off) - - Turns sprite translucency on and off. -
- SND_CHANNELS <integer> - - Sets the number of sound channels. -
- MUSICVOLUME <integer> - - Changes the music volume. -
- SOUNDVOLUME <integer> - - Changes the sound volume. -
- ALLOWTEAMCHANGE (yes/no) - - Allows players to change teams in CTF. (server only) -
- ALLOWAUTOAIM (yes/no) - - Allows players to use autoaim. (server only) -
- ALLOWEXITLEVEL (yes/no) - - Allows players to exit the level. (server only) -
- SHOWMESSAGES (on/off) - - Suppresses or enables some screen messages. -
- GAMMA <integer> - - Changes the gamma level. -
- COLOR <colorname> -

- COLOR2 <colorname> -

-
- Changes your player's color -
- NAME <name> -

- NAME2 <name> -

-
- Changes your player's name. -
- SKIN <name> -

- SKIN2 <name> -

-
- Changes your player's character. -
- FORCESKIN (on/off) - - Forces all players in the game to use the character that the server - is using. (server only) -
- PLAYDEMOSPEED <integer> - - Changes the speed at which a demo is played back. -
- NETSTAT (on/off) - - Shows network statistics. -
- TIMELIMIT <integer> - - Sets a time limit for multiplayer levels. (server only) -
- INTTIME <integer> - - Changes the intermission time in multiplayer levels. (server only) -
- AUTOCTF (yes/no) - - Auto-sorts people on teams as they join. (server only) -
- TIMETIC (on/off) - - Displays the time in game tics. -
- SERVERNAME <name> - - Changes the name of the server. -
- INTERNETSERVER (yes/no) - - Enables or disables advertising of the game on the master list. -
- VID_WAIT (on/off) - - Enables/Disables V-Sync. -
- VID_TICRATE (on/off) - - Shows game speed stats on a graph. -
-
-

- - Extras -

-

- knuckles.png (16482 bytes) -

-

- There are many add-ons and extra goodies for SRB2! Visit the Addons - section at www.srb2.org for a large - cache of downloads. -

-

- -

-
-

- - Troubleshooting -

-

- Have a problem? Question? Can't get SRB2 to work? Stop by the Forum at - www.srb2.org and ask. Someone will be - glad to help you work through the problem. -

-

- + + +

- + \ No newline at end of file diff --git a/readme.txt b/readme.txt index d8a040be0..176d29241 100644 --- a/readme.txt +++ b/readme.txt @@ -1,4 +1,4 @@ -Here it is! SRB2 v2.1.8 source code! +Here it is! SRB2 v2.1.9 source code! (why do we keep the version number up to date when everything else in this file is hilariously old? - Inuyasha) diff --git a/src/Makefile b/src/Makefile index f5d58af3a..3596c80aa 100644 --- a/src/Makefile +++ b/src/Makefile @@ -202,7 +202,7 @@ LIBS+=-lm endif ifdef SDL -include sdl/Makefile.cfg +include sdl2/Makefile.cfg endif #ifdef SDL ifdef DISTCC diff --git a/src/Makefile.cfg b/src/Makefile.cfg index 1ea96df92..e4f9290c6 100644 --- a/src/Makefile.cfg +++ b/src/Makefile.cfg @@ -386,7 +386,7 @@ OBJDUMP_OPTS?=--wide --source --line-numbers LD=$(CC) ifdef SDL - INTERFACE=sdl + INTERFACE=sdl2 OBJDIR:=$(OBJDIR)/SDL endif diff --git a/src/console.c b/src/console.c index 5f8dd2bb2..e77c400b3 100644 --- a/src/console.c +++ b/src/console.c @@ -1383,7 +1383,6 @@ static void CON_DrawConsole(void) UINT8 *p; size_t i; INT32 y; - INT32 w = 0, x2 = 0; INT32 charflags = 0; INT32 charwidth = (INT32)con_scalefactor << 3; INT32 charheight = charwidth; @@ -1416,9 +1415,9 @@ static void CON_DrawConsole(void) } else { - x2 = vid.width; - // Hurdler: what's the correct value of w and x2 in hardware mode??? - if (rendermode != render_none) V_DrawFadeConsBack(w, 0, x2, con_curlines, cons_backcolor.value); // translucent background + // inu: no more width (was always 0 and vid.width) + if (rendermode != render_none) + V_DrawFadeConsBack(con_curlines, cons_backcolor.value); // translucent background } // draw console text lines from top to bottom diff --git a/src/d_clisrv.c b/src/d_clisrv.c index dff495b10..b086077d4 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1041,6 +1041,40 @@ static void GetPackets(void); static cl_mode_t cl_mode = cl_searching; +// Player name send/load + +static void CV_SavePlayerNames(UINT8 **p) +{ + INT32 i = 0; + // Players in game only. + for (; i < MAXPLAYERS; ++i) + { + if (!playeringame[i]) + { + WRITEUINT8(*p, 0); + continue; + } + WRITESTRING(*p, player_names[i]); + } +} + +static void CV_LoadPlayerNames(UINT8 **p) +{ + INT32 i = 0; + char tmp_name[MAXPLAYERNAME+1]; + tmp_name[MAXPLAYERNAME] = 0; + + for (; i < MAXPLAYERS; ++i) + { + READSTRING(*p, tmp_name); + if (tmp_name[0] == 0) + continue; + if (tmp_name[MAXPLAYERNAME]) // overflow detected + I_Error("Received bad server config packet when trying to join"); + memcpy(player_names[i], tmp_name, MAXPLAYERNAME+1); + } +} + #ifdef CLIENT_LOADINGSCREEN // // CL_DrawConnectionStatus @@ -1070,6 +1104,7 @@ static inline void CL_DrawConnectionStatus(void) switch (cl_mode) { +#ifdef JOININGAME case cl_downloadsavegame: cltext = M_GetText("Downloading game state..."); Net_GetNetStat(); @@ -1078,6 +1113,7 @@ static inline void CL_DrawConnectionStatus(void) V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE, va("%3.1fK/s ", ((double)getbps)/1024)); break; +#endif case cl_askjoin: case cl_waitjoinresponse: cltext = M_GetText("Requesting to join..."); @@ -1257,27 +1293,38 @@ static boolean SV_SendServerConfig(INT32 node) INT32 i; UINT8 *p, *op; boolean waspacketsent; - UINT32 playermask = 0; netbuffer->packettype = PT_SERVERCFG; - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i]) - playermask |= 1<u.servercfg.version = VERSION; netbuffer->u.servercfg.subversion = SUBVERSION; netbuffer->u.servercfg.serverplayer = (UINT8)serverplayer; netbuffer->u.servercfg.totalslotnum = (UINT8)(doomcom->numslots); - netbuffer->u.servercfg.playerdetected = LONG(playermask); netbuffer->u.servercfg.gametic = (tic_t)LONG(gametic); netbuffer->u.servercfg.clientnode = (UINT8)node; netbuffer->u.servercfg.gamestate = (UINT8)gamestate; netbuffer->u.servercfg.gametype = (UINT8)gametype; netbuffer->u.servercfg.modifiedgame = (UINT8)modifiedgame; netbuffer->u.servercfg.adminplayer = (SINT8)adminplayer; + + // we fill these structs with FFs so that any players not in game get sent as 0xFFFF + // which is nice and easy for us to detect + memset(netbuffer->u.servercfg.playerskins, 0xFF, sizeof(netbuffer->u.servercfg.playerskins)); + memset(netbuffer->u.servercfg.playercolor, 0xFF, sizeof(netbuffer->u.servercfg.playercolor)); + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + netbuffer->u.servercfg.playerskins[i] = (UINT8)players[i].skin; + netbuffer->u.servercfg.playercolor[i] = (UINT8)players[i].skincolor; + } + memcpy(netbuffer->u.servercfg.server_context, server_context, 8); - op = p = netbuffer->u.servercfg.netcvarstates; + op = p = netbuffer->u.servercfg.varlengthinputs; + + CV_SavePlayerNames(&p); CV_SaveNetVars(&p); { const size_t len = sizeof (serverconfig_pak) + (size_t)(p - op); @@ -2063,7 +2110,7 @@ static void Command_connect(void) return; } - if (Playing()) + if (Playing() || titledemo) { CONS_Printf(M_GetText("You cannot connect while in a game. End this game first.\n")); return; @@ -3116,6 +3163,11 @@ static void HandleConnect(SINT8 node) SV_AddWaitingPlayers(); player_joining = true; } +#else +#ifndef NONET + // I guess we have no use for this if we aren't doing mid-level joins? + (void)newnode; +#endif #endif } } @@ -3248,7 +3300,6 @@ FILESTAMP { INT32 j; UINT8 *scp; - UINT32 playermask = 0; if (server && serverrunning && node != servernode) { // but wait I thought I'm the server? @@ -3283,11 +3334,20 @@ FILESTAMP #endif DEBFILE(va("Server accept join gametic=%u mynode=%d\n", gametic, mynode)); - playermask = LONG(netbuffer->u.servercfg.playerdetected); + memset(playeringame, 0, sizeof(playeringame)); for (j = 0; j < MAXPLAYERS; j++) - playeringame[j] = (playermask & (1<u.servercfg.playerskins[j] == 0xFF + && netbuffer->u.servercfg.playercolor[j] == 0xFF) + continue; // not in game - scp = netbuffer->u.servercfg.netcvarstates; + playeringame[j] = true; + SetPlayerSkinByNum(j, (INT32)netbuffer->u.servercfg.playerskins[j]); + players[j].skincolor = netbuffer->u.servercfg.playercolor[j]; + } + + scp = netbuffer->u.servercfg.varlengthinputs; + CV_LoadPlayerNames(&scp); CV_LoadNetVars(&scp); #ifdef JOININGAME if (netbuffer->u.servercfg.gamestate == GS_LEVEL/* || diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 0086132e6..700fb5f67 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -267,14 +267,17 @@ typedef struct UINT8 clientnode; UINT8 gamestate; - UINT32 playerdetected; // playeringame vector in bit field + // 0xFF == not in game; else player skin num + UINT8 playerskins[MAXPLAYERS]; + UINT8 playercolor[MAXPLAYERS]; + UINT8 gametype; UINT8 modifiedgame; SINT8 adminplayer; // needs to be signed char server_context[8]; // unique context id, generated at server startup. - UINT8 netcvarstates[0]; + UINT8 varlengthinputs[0]; // playernames and netvars } ATTRPACK serverconfig_pak; typedef struct { diff --git a/src/d_main.c b/src/d_main.c index b0d248ef2..42734fbc9 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -659,6 +659,7 @@ void D_StartTitle(void) // okay, stop now // (otherwise the game still thinks we're playing!) SV_StopServer(); + SV_ResetServer(); // In case someone exits out at the same time they start a time attack run, // reset modeattacking @@ -1086,14 +1087,14 @@ void D_SRB2Main(void) #endif D_CleanFile(); -#if 1 // md5s last updated 4/13/14 +#if 1 // md5s last updated 8/03/14 // Check MD5s of autoloaded files W_VerifyFileMD5(0, "ac309fb3c7d4b5b685e2cd26beccf0e8"); // srb2.srb/srb2.wad W_VerifyFileMD5(1, "e956466eff2c79f7b1cdefad24761bce"); // zones.dta W_VerifyFileMD5(2, "95a4cdbed287323dd361243f357a5fd2"); // player.dta W_VerifyFileMD5(3, "85901ad4bf94637e5753d2ac2c03ea26"); // rings.dta - W_VerifyFileMD5(4, "1f37fe7bcc608a23eadb0e2c2d7c7124"); // patch.dta + W_VerifyFileMD5(4, "636e4c7b71e770e8368b48fcfe07bbd8"); // patch.dta // don't check music.dta because people like to modify it, and it doesn't matter if they do // ...except it does if they slip maps in there, and that's what W_VerifyNMUSlumps is for. #endif diff --git a/src/d_net.c b/src/d_net.c index 906c53890..d13c4bd25 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -800,9 +800,8 @@ static void DebugPrintpacket(const char *header) fprintfstring((char *)netbuffer->u.textcmd+1, netbuffer->u.textcmd[0]); break; case PT_SERVERCFG: - fprintf(debugfile, " playermask %x playerslots %d clientnode %d serverplayer %d " + fprintf(debugfile, " playerslots %d clientnode %d serverplayer %d " "gametic %u gamestate %d gametype %d modifiedgame %d\n", - (UINT32)LONG(netbuffer->u.servercfg.playerdetected), netbuffer->u.servercfg.totalslotnum, netbuffer->u.servercfg.clientnode, netbuffer->u.servercfg.serverplayer, (UINT32)LONG(netbuffer->u.servercfg.gametic), netbuffer->u.servercfg.gamestate, netbuffer->u.servercfg.gametype, diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 62531598a..dd7435bde 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -106,8 +106,6 @@ static void Command_Stopdemo_f(void); static void Command_StartMovie_f(void); static void Command_StopMovie_f(void); static void Command_Map_f(void); -static void Command_Teleport_f(void); -static void Command_RTeleport_f(void); static void Command_ResetCamera_f(void); static void Command_Addfile(void); @@ -124,13 +122,11 @@ static void Command_Version_f(void); static void Command_ModDetails_f(void); #endif static void Command_ShowGametype_f(void); -static void Command_JumpToAxis_f(void); FUNCNORETURN static ATTRNORETURN void Command_Quit_f(void); static void Command_Playintro_f(void); static void Command_Displayplayer_f(void); static void Command_Tunes_f(void); -static void Command_Skynum_f(void); static void Command_ExitLevel_f(void); static void Command_Showmap_f(void); @@ -333,7 +329,7 @@ consvar_t cv_overtime = {"overtime", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL, consvar_t cv_rollingdemos = {"rollingdemos", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_timetic = {"timerres", "Normal", 0, timetic_cons_t, NULL, CV_SAVE, NULL, NULL, 0, 0, NULL}; // use tics in display +consvar_t cv_timetic = {"timerres", "Normal", CV_SAVE, timetic_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; // use tics in display consvar_t cv_resetmusic = {"resetmusic", "No", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t pointlimit_cons_t[] = {{0, "MIN"}, {999999990, "MAX"}, {0, NULL}}; @@ -444,7 +440,6 @@ void D_RegisterServerCommands(void) COM_AddCommand("suicide", Command_Suicide); COM_AddCommand("gametype", Command_ShowGametype_f); - COM_AddCommand("jumptoaxis", Command_JumpToAxis_f); COM_AddCommand("version", Command_Version_f); #ifdef UPDATE_ALERT COM_AddCommand("mod_details", Command_ModDetails_f); @@ -766,11 +761,13 @@ void D_RegisterClientCommands(void) COM_AddCommand("scale", Command_Scale_f); COM_AddCommand("gravflip", Command_Gravflip_f); COM_AddCommand("hurtme", Command_Hurtme_f); + COM_AddCommand("jumptoaxis", Command_JumpToAxis_f); COM_AddCommand("charability", Command_Charability_f); COM_AddCommand("charspeed", Command_Charspeed_f); COM_AddCommand("teleport", Command_Teleport_f); COM_AddCommand("rteleport", Command_RTeleport_f); COM_AddCommand("skynum", Command_Skynum_f); + COM_AddCommand("weather", Command_Weather_f); #ifdef _DEBUG COM_AddCommand("causecfail", Command_CauseCfail_f); #endif @@ -1384,149 +1381,6 @@ static void Command_ResetCamera_f(void) P_ResetCamera(&players[displayplayer], &camera); } -static void Command_RTeleport_f(void) -{ - fixed_t intx, inty, intz; - size_t i; - player_t *p = &players[consoleplayer]; - subsector_t *ss; - - if (!(cv_debug || devparm)) - { - CONS_Printf(M_GetText("DEVMODE must be enabled.")); - return; - } - if (netgame) - { - CONS_Printf(M_GetText("This only works in single player.\n")); - return; - } - - if (COM_Argc() < 3 || COM_Argc() > 7) - { - CONS_Printf(M_GetText("rteleport -x -y -z : relative teleport to a location\n")); - return; - } - - if (!p->mo) - return; - - i = COM_CheckParm("-x"); - if (i) - intx = atoi(COM_Argv(i + 1)); - else - intx = 0; - - i = COM_CheckParm("-y"); - if (i) - inty = atoi(COM_Argv(i + 1)); - else - inty = 0; - - ss = R_PointInSubsector(p->mo->x + intx*FRACUNIT, p->mo->y + inty*FRACUNIT); - if (!ss || ss->sector->ceilingheight - ss->sector->floorheight < p->mo->height) - { - CONS_Alert(CONS_NOTICE, M_GetText("Not a valid location.\n")); - return; - } - i = COM_CheckParm("-z"); - if (i) - { - intz = atoi(COM_Argv(i + 1)); - intz <<= FRACBITS; - intz += p->mo->z; - if (intz < ss->sector->floorheight) - intz = ss->sector->floorheight; - if (intz > ss->sector->ceilingheight - p->mo->height) - intz = ss->sector->ceilingheight - p->mo->height; - } - else - intz = 0; - - CONS_Printf(M_GetText("Teleporting by %d, %d, %d...\n"), intx, inty, FixedInt((intz-p->mo->z))); - - P_MapStart(); - if (!P_TeleportMove(p->mo, p->mo->x+intx*FRACUNIT, p->mo->y+inty*FRACUNIT, intz)) - CONS_Alert(CONS_WARNING, M_GetText("Unable to teleport to that spot!\n")); - else - S_StartSound(p->mo, sfx_mixup); - P_MapEnd(); -} - -static void Command_Teleport_f(void) -{ - fixed_t intx, inty, intz; - size_t i; - player_t *p = &players[consoleplayer]; - subsector_t *ss; - - if (!(cv_debug || devparm)) - { - CONS_Printf(M_GetText("DEVMODE must be enabled.")); - return; - } - if (netgame) - { - CONS_Printf(M_GetText("This only works in single player.\n")); - return; - } - - if (COM_Argc() < 3 || COM_Argc() > 7) - { - CONS_Printf(M_GetText("teleport -x -y -z : teleport to a location\n")); - return; - } - - if (!p->mo) - return; - - i = COM_CheckParm("-x"); - if (i) - intx = atoi(COM_Argv(i + 1)); - else - { - CONS_Alert(CONS_NOTICE, M_GetText("%s value not specified\n"), "X"); - return; - } - - i = COM_CheckParm("-y"); - if (i) - inty = atoi(COM_Argv(i + 1)); - else - { - CONS_Alert(CONS_NOTICE, M_GetText("%s value not specified\n"), "Y"); - return; - } - - ss = R_PointInSubsector(intx*FRACUNIT, inty*FRACUNIT); - if (!ss || ss->sector->ceilingheight - ss->sector->floorheight < p->mo->height) - { - CONS_Alert(CONS_NOTICE, M_GetText("Not a valid location.\n")); - return; - } - i = COM_CheckParm("-z"); - if (i) - { - intz = atoi(COM_Argv(i + 1)); - intz <<= FRACBITS; - if (intz < ss->sector->floorheight) - intz = ss->sector->floorheight; - if (intz > ss->sector->ceilingheight - p->mo->height) - intz = ss->sector->ceilingheight - p->mo->height; - } - else - intz = ss->sector->floorheight; - - CONS_Printf(M_GetText("Teleporting to %d, %d, %d...\n"), intx, inty, FixedInt(intz)); - - P_MapStart(); - if (!P_TeleportMove(p->mo, intx*FRACUNIT, inty*FRACUNIT, intz)) - CONS_Alert(CONS_WARNING, M_GetText("Unable to teleport to that spot!\n")); - else - S_StartSound(p->mo, sfx_mixup); - P_MapEnd(); -} - // ======================================================================== // play a demo, add .lmp for external demos @@ -3359,23 +3213,6 @@ static void Command_ShowGametype_f(void) CONS_Printf(M_GetText("Current gametype is %d\n"), gametype); } -// Moves the NiGHTS player to another axis within the current mare -// Only for development purposes. -// -static void Command_JumpToAxis_f(void) -{ - if (!cv_debug) - CONS_Printf(M_GetText("DEVMODE must be enabled.\n")); - - if (COM_Argc() != 2) - { - CONS_Printf(M_GetText("jumptoaxis : Jump to axis within current mare.\n")); - return; - } - - P_TransferToAxis(&players[consoleplayer], atoi(COM_Argv(1))); -} - /** Plays the intro. */ static void Command_Playintro_f(void) @@ -3926,32 +3763,6 @@ static void Command_Displayplayer_f(void) CONS_Printf(M_GetText("Displayplayer is %d\n"), displayplayer); } -static void Command_Skynum_f(void) -{ - if (!cv_debug) - { - CONS_Printf(M_GetText("DEVMODE must be enabled.\n")); - CONS_Printf(M_GetText("If you want to change the sky interactively on a map, use the linedef executor feature instead.\n")); - return; - } - - if (netgame || multiplayer) - { - CONS_Printf(M_GetText("This only works in single player.\n")); - return; - } - - if (COM_Argc() != 2) - { - CONS_Printf(M_GetText("skynum : change the sky\n")); - return; - } - - CONS_Printf(M_GetText("Previewing sky %s...\n"), COM_Argv(1)); - - P_SetupLevelSky(atoi(COM_Argv(1)), false); -} - static void Command_Tunes_f(void) { const char *tunearg; diff --git a/src/d_player.h b/src/d_player.h index 3bced1a8b..b0484f0a1 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -149,7 +149,10 @@ typedef enum PF_TAGGED = 1<<27, // Player has been tagged and awaits the next round in hide and seek. PF_TAGIT = 1<<28, // The player is it! For Tag Mode - // free: 1<<29 through 1<<31 + /*** misc ***/ + PF_FORCESTRAFE = 1<<29, // Turning inputs are translated into strafing inputs + + // free: 1<<30 and 1<<31 } pflags_t; typedef enum diff --git a/src/dehacked.c b/src/dehacked.c index 37bd52950..5149fddd5 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -27,6 +27,7 @@ #include "p_local.h" // for var1 and var2, and some constants #include "p_setup.h" #include "r_data.h" +#include "r_sky.h" #include "fastcmp.h" #include "lua_script.h" #include "lua_hook.h" @@ -364,6 +365,10 @@ static void clear_levels(void) if (!mapheaderinfo[i]) continue; + // Custom map header info + // (no need to set num to 0, we're freeing the entire header shortly) + Z_Free(mapheaderinfo[i]->customopts); + P_DeleteGrades(i); Z_Free(mapheaderinfo[i]); mapheaderinfo[i] = NULL; @@ -991,6 +996,7 @@ static void readlevelheader(MYFILE *f, INT32 num) char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); char *word = s; char *word2; + //char *word3; // Non-uppercase version of word2 char *tmp; INT32 i; @@ -1034,6 +1040,49 @@ static void readlevelheader(MYFILE *f, INT32 num) continue; } + // Lua custom options also go above, contents may be case sensitive. + if (fastncmp(word, "LUA.", 4)) + { +#ifdef HAVE_BLUA + UINT8 j; + customoption_t *modoption; + + // Note: we actualy strlwr word here, so things are made a little easier for Lua + strlwr(word); + word += 4; // move past "lua." + + // ... and do a simple name sanity check; the name must start with a letter + if (*word < 'a' || *word > 'z') + { + deh_warning("Level header %d: invalid custom option name \"%s\"", num, word); + continue; + } + + // Sanity limit of 128 params + if (mapheaderinfo[num-1]->numCustomOptions == 128) + { + deh_warning("Level header %d: too many custom parameters", num); + continue; + } + j = mapheaderinfo[num-1]->numCustomOptions++; + + mapheaderinfo[num-1]->customopts = + Z_Realloc(mapheaderinfo[num-1]->customopts, + sizeof(customoption_t) * mapheaderinfo[num-1]->numCustomOptions, PU_STATIC, NULL); + + // Newly allocated + modoption = &mapheaderinfo[num-1]->customopts[j]; + + strncpy(modoption->option, word, 31); + modoption->option[31] = '\0'; + strncpy(modoption->value, word2, 255); + modoption->value[255] = '\0'; +#else + // Silently ignore. +#endif + continue; + } + // Now go to uppercase strupr(word2); @@ -1047,19 +1096,26 @@ static void readlevelheader(MYFILE *f, INT32 num) deh_warning("Level header %d: unknown word '%s'", num, word); continue; } + P_AddGradesForMare((INT16)(num-1), mare-1, word2); } // Strings that can be truncated else if (fastcmp(word, "LEVELNAME")) + { deh_strlcpy(mapheaderinfo[num-1]->lvlttl, word2, sizeof(mapheaderinfo[num-1]->lvlttl), va("Level header %d: levelname", num)); + } else if (fastcmp(word, "SCRIPTNAME")) + { deh_strlcpy(mapheaderinfo[num-1]->scriptname, word2, sizeof(mapheaderinfo[num-1]->scriptname), va("Level header %d: scriptname", num)); + } else if (fastcmp(word, "RUNSOC")) + { deh_strlcpy(mapheaderinfo[num-1]->runsoc, word2, sizeof(mapheaderinfo[num-1]->runsoc), va("Level header %d: runsoc", num)); + } else if (fastcmp(word, "ACT")) { if (i >= 0 && i < 20) // 0 for no act number, TTL1 through TTL19 @@ -1240,7 +1296,6 @@ static void readlevelheader(MYFILE *f, INT32 num) else mapheaderinfo[num-1]->menuflags &= ~LF2_NOVISITNEEDED; } - else deh_warning("Level header %d: unknown word '%s'", num, word); } @@ -7145,23 +7200,11 @@ static const char *const MOBJEFLAG_LIST[] = { NULL }; -static const char *const MAPTHINGFLAG_LIST[16] = { +static const char *const MAPTHINGFLAG_LIST[4] = { NULL, "OBJECTFLIP", // Reverse gravity flag for objects. "OBJECTSPECIAL", // Special flag used with certain objects. - "AMBUSH", // Deaf monsters/do not react to sound. - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL + "AMBUSH" // Deaf monsters/do not react to sound. }; static const char *const PLAYERFLAG_LIST[] = { @@ -7228,6 +7271,9 @@ static const char *const PLAYERFLAG_LIST[] = { "TAGGED", // Player has been tagged and awaits the next round in hide and seek. "TAGIT", // The player is it! For Tag Mode + /*** misc ***/ + "FORCESTRAFE", // Translate turn inputs into strafe inputs + NULL // stop loop here. }; @@ -7443,6 +7489,19 @@ struct { {"TOL_ERZ3",TOL_ERZ3}, {"TOL_XMAS",TOL_XMAS}, + // Level flags + {"LF_SCRIPTISFILE",LF_SCRIPTISFILE}, + {"LF_SPEEDMUSIC",LF_SPEEDMUSIC}, + {"LF_NOSSMUSIC",LF_NOSSMUSIC}, + {"LF_NORELOAD",LF_NORELOAD}, + {"LF_NOZONE",LF_NOZONE}, + // And map flags + {"LF2_HIDEINMENU",LF2_HIDEINMENU}, + {"LF2_HIDEINSTATS",LF2_HIDEINSTATS}, + {"LF2_RECORDATTACK",LF2_RECORDATTACK}, + {"LF2_NIGHTSATTACK",LF2_NIGHTSATTACK}, + {"LF2_NOVISITNEEDED",LF2_NOVISITNEEDED}, + // NiGHTS grades {"GRADE_F",GRADE_F}, {"GRADE_E",GRADE_E}, @@ -7592,6 +7651,68 @@ struct { {"GF_REDFLAG",GF_REDFLAG}, {"GF_BLUEFLAG",GF_BLUEFLAG}, + // Customisable sounds for Skins, from sounds.h + {"SKSSPIN",SKSSPIN}, + {"SKSPUTPUT",SKSPUTPUT}, + {"SKSPUDPUD",SKSPUDPUD}, + {"SKSPLPAN1",SKSPLPAN1}, // Ouchies + {"SKSPLPAN2",SKSPLPAN2}, + {"SKSPLPAN3",SKSPLPAN3}, + {"SKSPLPAN4",SKSPLPAN4}, + {"SKSPLDET1",SKSPLDET1}, // Deaths + {"SKSPLDET2",SKSPLDET2}, + {"SKSPLDET3",SKSPLDET3}, + {"SKSPLDET4",SKSPLDET4}, + {"SKSPLVCT1",SKSPLVCT1}, // Victories + {"SKSPLVCT2",SKSPLVCT2}, + {"SKSPLVCT3",SKSPLVCT3}, + {"SKSPLVCT4",SKSPLVCT4}, + {"SKSTHOK",SKSTHOK}, + {"SKSSPNDSH",SKSSPNDSH}, + {"SKSZOOM",SKSZOOM}, + {"SKSSKID",SKSSKID}, + {"SKSGASP",SKSGASP}, + {"SKSJUMP",SKSJUMP}, + + // 3D Floor/Fake Floor/FOF/whatever flags + {"FF_EXISTS",FF_EXISTS}, ///< Always set, to check for validity. + {"FF_BLOCKPLAYER",FF_BLOCKPLAYER}, ///< Solid to player, but nothing else + {"FF_BLOCKOTHERS",FF_BLOCKOTHERS}, ///< Solid to everything but player + {"FF_SOLID",FF_SOLID}, ///< Clips things. + {"FF_RENDERSIDES",FF_RENDERSIDES}, ///< Renders the sides. + {"FF_RENDERPLANES",FF_RENDERPLANES}, ///< Renders the floor/ceiling. + {"FF_RENDERALL",FF_RENDERALL}, ///< Renders everything. + {"FF_SWIMMABLE",FF_SWIMMABLE}, ///< Is a water block. + {"FF_NOSHADE",FF_NOSHADE}, ///< Messes with the lighting? + {"FF_CUTSOLIDS",FF_CUTSOLIDS}, ///< Cuts out hidden solid pixels. + {"FF_CUTEXTRA",FF_CUTEXTRA}, ///< Cuts out hidden translucent pixels. + {"FF_CUTLEVEL",FF_CUTLEVEL}, ///< Cuts out all hidden pixels. + {"FF_CUTSPRITES",FF_CUTSPRITES}, ///< Final step in making 3D water. + {"FF_BOTHPLANES",FF_BOTHPLANES}, ///< Renders both planes all the time. + {"FF_EXTRA",FF_EXTRA}, ///< Gets cut by ::FF_CUTEXTRA. + {"FF_TRANSLUCENT",FF_TRANSLUCENT}, ///< See through! + {"FF_FOG",FF_FOG}, ///< Fog "brush." + {"FF_INVERTPLANES",FF_INVERTPLANES}, ///< Reverse the plane visibility rules. + {"FF_ALLSIDES",FF_ALLSIDES}, ///< Render inside and outside sides. + {"FF_INVERTSIDES",FF_INVERTSIDES}, ///< Only render inside sides. + {"FF_DOUBLESHADOW",FF_DOUBLESHADOW}, ///< Make two lightlist entries to reset light? + {"FF_FLOATBOB",FF_FLOATBOB}, ///< Floats on water and bobs if you step on it. + {"FF_NORETURN",FF_NORETURN}, ///< Used with ::FF_CRUMBLE. Will not return to its original position after falling. + {"FF_CRUMBLE",FF_CRUMBLE}, ///< Falls 2 seconds after being stepped on, and randomly brings all touching crumbling 3dfloors down with it, providing their master sectors share the same tag (allows crumble platforms above or below, to also exist). + {"FF_SHATTERBOTTOM",FF_SHATTERBOTTOM}, ///< Used with ::FF_BUSTUP. Like FF_SHATTER, but only breaks from the bottom. Good for springing up through rubble. + {"FF_MARIO",FF_MARIO}, ///< Acts like a question block when hit from underneath. Goodie spawned at top is determined by master sector. + {"FF_BUSTUP",FF_BUSTUP}, ///< You can spin through/punch this block and it will crumble! + {"FF_QUICKSAND",FF_QUICKSAND}, ///< Quicksand! + {"FF_PLATFORM",FF_PLATFORM}, ///< You can jump up through this to the top. + {"FF_REVERSEPLATFORM",FF_REVERSEPLATFORM}, ///< A fall-through floor in normal gravity, a platform in reverse gravity. + {"FF_INTANGABLEFLATS",FF_INTANGABLEFLATS}, ///< Both flats are intangable, but the sides are still solid. + {"FF_SHATTER",FF_SHATTER}, ///< Used with ::FF_BUSTUP. Thinks everyone's Knuckles. + {"FF_SPINBUST",FF_SPINBUST}, ///< Used with ::FF_BUSTUP. Jump or fall onto it while curled in a ball. + {"FF_ONLYKNUX",FF_ONLYKNUX}, ///< Used with ::FF_BUSTUP. Only Knuckles can break this rock. + {"FF_RIPPLE",FF_RIPPLE}, ///< Ripple the flats + {"FF_COLORMAPONLY",FF_COLORMAPONLY}, ///< Only copy the colormap, not the lightlevel + {"FF_GOOWATER",FF_GOOWATER}, ///< Used with ::FF_SWIMMABLE. Makes thick bouncey goop. + // Angles {"ANG1",ANG1}, {"ANG2",ANG2}, @@ -8268,7 +8389,7 @@ static inline int lib_getenum(lua_State *L) } else if (fastncmp("MTF_", word, 4)) { p = word+4; - for (i = 0; i < 16; i++) + for (i = 0; i < 4; i++) if (MAPTHINGFLAG_LIST[i] && fastcmp(p, MAPTHINGFLAG_LIST[i])) { lua_pushinteger(L, ((lua_Integer)1<mo && (player->mo->flags2 & MF2_TWOD)) || player->climbing || (player->pflags & PF_NIGHTSMODE) - || (player->pflags & PF_SLIDING)) // Analog + || (player->pflags & PF_SLIDING) + || (player->pflags & PF_FORCESTRAFE)) // Analog forcestrafe = true; if (forcestrafe) // Analog { @@ -1243,7 +1244,8 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics) || (player->mo && (player->mo->flags2 & MF2_TWOD)) || player->climbing || (player->pflags & PF_NIGHTSMODE) - || (player->pflags & PF_SLIDING)) // Analog + || (player->pflags & PF_SLIDING) + || (player->pflags & PF_FORCESTRAFE)) // Analog forcestrafe = true; if (forcestrafe) // Analog { @@ -2421,6 +2423,8 @@ void G_DoReborn(INT32 playernum) { INT32 i; + player->playerstate = PST_REBORN; + P_LoadThingsOnly(); P_ClearStarPost(player->starpostnum); @@ -2451,6 +2455,12 @@ void G_DoReborn(INT32 playernum) // Starpost support G_SpawnPlayer(playernum, starpost); + + if (botingame) + { // Bots respawn next to their master. + players[secondarydisplayplayer].playerstate = PST_REBORN; + G_SpawnPlayer(secondarydisplayplayer, false); + } } else #ifdef HAVE_BLUA @@ -5175,19 +5185,26 @@ void G_AddGhost(char *defdemoname) I_Assert(mthing); { // A bit more complex than P_SpawnPlayer because ghosts aren't solid and won't just push themselves out of the ceiling. fixed_t x,y,z; + sector_t *sector; x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; - if (mthing->options & MTF_AMBUSH) - z = R_PointInSubsector(x, y)->sector->ceilingheight - mobjinfo[MT_PLAYER].height; - else if (mthing->options >> ZSHIFT) + sector = R_PointInSubsector(x, y)->sector; + if (!!(mthing->options & MTF_AMBUSH) ^ !!(mthing->options & MTF_OBJECTFLIP)) { - sector_t *sector = R_PointInSubsector(x, y)->sector; - z = sector->floorheight + ((mthing->options >> ZSHIFT) << FRACBITS); + z = sector->ceilingheight - mobjinfo[MT_PLAYER].height; + if (mthing->options >> ZSHIFT) + z -= ((mthing->options >> ZSHIFT) << FRACBITS); + if (z < sector->floorheight) + z = sector->floorheight; + } + else + { + z = sector->floorheight; + if (mthing->options >> ZSHIFT) + z += ((mthing->options >> ZSHIFT) << FRACBITS); if (z > sector->ceilingheight - mobjinfo[MT_PLAYER].height) z = sector->ceilingheight - mobjinfo[MT_PLAYER].height; } - else - z = mthing->z << FRACBITS; gh->mo = P_SpawnMobj(x, y, z, MT_GHOST); gh->mo->angle = FixedAngle(mthing->angle*FRACUNIT); } diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 4f5acca86..9cc4f5625 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -116,10 +116,6 @@ consvar_t cv_granisotropicmode = {"gr_anisotropicmode", "1", CV_CALL, granisotro consvar_t cv_grcorrecttricks = {"gr_correcttricks", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_grsolvetjoin = {"gr_solvetjoin", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -static CV_PossibleValue_t CV_MD2[] = {{0, "Off"}, {1, "On"}, {2, "Old"}, {0, NULL}}; -// console variables in development -consvar_t cv_grmd2 = {"gr_md2", "Off", 0, CV_MD2, NULL, 0, NULL, NULL, 0, 0, NULL}; - static void CV_FogDensity_ONChange(void) { HWD.pfnSetSpecialState(HWD_SET_FOG_DENSITY, cv_grfogdensity.value); @@ -4966,7 +4962,6 @@ static void Command_GrStats_f(void) //added by Hurdler: console varibale that are saved void HWR_AddCommands(void) { - CV_RegisterVar(&cv_grmd2); CV_RegisterVar(&cv_grrounddown); CV_RegisterVar(&cv_grfov); CV_RegisterVar(&cv_grfogdensity); diff --git a/src/info.c b/src/info.c index 01c258e44..a964ae80e 100644 --- a/src/info.c +++ b/src/info.c @@ -829,7 +829,7 @@ state_t states[NUMSTATES] = {SPR_NULL, 0, 0, {A_Repeat}, 5*TICRATE, S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMCHECK, S_CYBRAKDEMONELECTRICBARRIER_REVIVE1}, // S_CYBRAKDEMONELECTRICBARRIER_SPARK_RANDOMLOOP, {SPR_NULL, 0, 0, {A_CapeChase}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_REVIVE2}, // S_CYBRAKDEMONELECTRICBARRIER_REVIVE1 {SPR_NULL, 0, 0, {A_SpawnFreshCopy}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_REVIVE3}, // S_CYBRAKDEMONELECTRICBARRIER_REVIVE2 - {SPR_NULL, 0, TICRATE, {A_PlaySound}, sfx_s3k79, 0, S_NULL}, // S_CYBRAKDEMONELECTRICBARRIER_INIT1 + {SPR_NULL, 0, TICRATE, {A_PlaySound}, sfx_s3k79, 0, S_NULL}, // S_CYBRAKDEMONELECTRICBARRIER_REVIVE3 {SPR_TARG, 0 + FF_FULLBRIGHT, 1, {A_VileFire}, sfx_s3k9d, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE2}, // S_CYBRAKDEMONTARGETRETICULE1 {SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE3}, // S_CYBRAKDEMONTARGETRETICULE2 diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 38ed69061..d84d3b3a6 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -468,6 +468,19 @@ static int lib_pSetScale(lua_State *L) return 0; } +static int lib_pInsideANonSolidFFloor(lua_State *L) +{ + mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + ffloor_t *rover = *((ffloor_t **)luaL_checkudata(L, 2, META_FFLOOR)); + //HUDSAFE + if (!mobj) + return LUA_ErrInvalid(L, "mobj_t"); + if (!rover) + return LUA_ErrInvalid(L, "ffloor_t"); + lua_pushboolean(L, P_InsideANonSolidFFloor(mobj, rover)); + return 1; +} + static int lib_pCheckDeathPitCollide(lua_State *L) { mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); @@ -478,6 +491,32 @@ static int lib_pCheckDeathPitCollide(lua_State *L) return 1; } +static int lib_pCheckSolidLava(lua_State *L) +{ + mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + ffloor_t *rover = *((ffloor_t **)luaL_checkudata(L, 2, META_FFLOOR)); + //HUDSAFE + if (!mo) + return LUA_ErrInvalid(L, "mobj_t"); + if (!rover) + return LUA_ErrInvalid(L, "ffloor_t"); + lua_pushboolean(L, P_CheckSolidLava(mo, rover)); + return 1; +} + +static int lib_pCanRunOnWater(lua_State *L) +{ + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + ffloor_t *rover = *((ffloor_t **)luaL_checkudata(L, 2, META_FFLOOR)); + //HUDSAFE + if (!player) + return LUA_ErrInvalid(L, "player_t"); + if (!rover) + return LUA_ErrInvalid(L, "ffloor_t"); + lua_pushboolean(L, P_CanRunOnWater(player, rover)); + return 1; +} + // P_USER //////////// @@ -539,9 +578,9 @@ static int lib_pDoPlayerPain(lua_State *L) NOHUD if (!player) return LUA_ErrInvalid(L, "player_t"); - if (!lua_isnone(L, 2) && lua_touserdata(L, 2)) + if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) source = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ)); - if (!lua_isnone(L, 3) && lua_touserdata(L, 3)) + if (!lua_isnone(L, 3) && lua_isuserdata(L, 3)) inflictor = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); P_DoPlayerPain(player, source, inflictor); return 0; @@ -557,6 +596,16 @@ static int lib_pResetPlayer(lua_State *L) return 0; } +static int lib_pIsObjectInGoop(lua_State *L) +{ + mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + //HUDSAFE + if (!mo) + return LUA_ErrInvalid(L, "mobj_t"); + lua_pushboolean(L, P_IsObjectInGoop(mo)); + return 1; +} + static int lib_pIsObjectOnGround(lua_State *L) { mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); @@ -567,6 +616,26 @@ static int lib_pIsObjectOnGround(lua_State *L) return 1; } +static int lib_pInSpaceSector(lua_State *L) +{ + mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + //HUDSAFE + if (!mo) + return LUA_ErrInvalid(L, "mobj_t"); + lua_pushboolean(L, P_InSpaceSector(mo)); + return 1; +} + +static int lib_pInQuicksand(lua_State *L) +{ + mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + //HUDSAFE + if (!mo) + return LUA_ErrInvalid(L, "mobj_t"); + lua_pushboolean(L, P_InQuicksand(mo)); + return 1; +} + static int lib_pSetObjectMomZ(lua_State *L) { mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); @@ -589,6 +658,16 @@ static int lib_pRestoreMusic(lua_State *L) return 0; } +static int lib_pSpawnShieldOrb(lua_State *L) +{ + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + NOHUD + if (!player) + return LUA_ErrInvalid(L, "player_t"); + P_SpawnShieldOrb(player); + return 0; +} + static int lib_pSpawnGhostMobj(lua_State *L) { mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); @@ -631,6 +710,16 @@ static int lib_pResetScore(lua_State *L) return 0; } +static int lib_pDoJumpShield(lua_State *L) +{ + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + NOHUD + if (!player) + return LUA_ErrInvalid(L, "player_t"); + P_DoJumpShield(player); + return 0; +} + static int lib_pBlackOw(lua_State *L) { player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); @@ -788,7 +877,6 @@ static int lib_pTelekinesis(lua_State *L) return 0; } - // P_MAP /////////// @@ -952,9 +1040,9 @@ static int lib_pDamageMobj(lua_State *L) NOHUD if (!target) return LUA_ErrInvalid(L, "mobj_t"); - if (!lua_isnone(L, 2) && lua_touserdata(L, 2)) + if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) inflictor = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ)); - if (!lua_isnone(L, 3) && lua_touserdata(L, 3)) + if (!lua_isnone(L, 3) && lua_isuserdata(L, 3)) source = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); damage = (INT32)luaL_optinteger(L, 4, 1); lua_pushboolean(L, P_DamageMobj(target, inflictor, source, damage)); @@ -967,9 +1055,9 @@ static int lib_pKillMobj(lua_State *L) NOHUD if (!target) return LUA_ErrInvalid(L, "mobj_t"); - if (!lua_isnone(L, 2) && lua_touserdata(L, 2)) + if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) inflictor = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ)); - if (!lua_isnone(L, 3) && lua_touserdata(L, 3)) + if (!lua_isnone(L, 3) && lua_isuserdata(L, 3)) source = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); P_KillMobj(target, inflictor, source); return 0; @@ -1033,30 +1121,54 @@ static int lib_pPlayerFlagBurst(lua_State *L) static int lib_pPlayRinglossSound(lua_State *L) { mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + player_t *player = NULL; NOHUD if (!source) return LUA_ErrInvalid(L, "mobj_t"); - P_PlayRinglossSound(source); + if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) + { + player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) + P_PlayRinglossSound(source); return 0; } static int lib_pPlayDeathSound(lua_State *L) { mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + player_t *player = NULL; NOHUD if (!source) return LUA_ErrInvalid(L, "mobj_t"); - P_PlayDeathSound(source); + if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) + { + player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) + P_PlayDeathSound(source); return 0; } static int lib_pPlayVictorySound(lua_State *L) { mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + player_t *player = NULL; NOHUD if (!source) return LUA_ErrInvalid(L, "mobj_t"); - P_PlayVictorySound(source); + if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) + { + player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) + P_PlayVictorySound(source); return 0; } @@ -1165,8 +1277,14 @@ static int lib_pFindSpecialLineFromTag(lua_State *L) static int lib_pSwitchWeather(lua_State *L) { INT32 weathernum = (INT32)luaL_checkinteger(L, 1); + player_t *user = NULL; NOHUD - P_SwitchWeather(weathernum); + if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) // if a player, setup weather for only the player, otherwise setup weather for all players + user = *((player_t **)luaL_checkudata(L, 2, META_PLAYER)); + if (!user) // global + globalweather = weathernum; + if (!user || P_IsLocalPlayer(user)) + P_SwitchWeather(weathernum); return 0; } @@ -1227,9 +1345,14 @@ static int lib_pIsFlagAtBase(lua_State *L) static int lib_pSetupLevelSky(lua_State *L) { INT32 skynum = (INT32)luaL_checkinteger(L, 1); - boolean global = lua_optboolean(L, 2); + player_t *user = NULL; NOHUD - P_SetupLevelSky(skynum, global); + if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) // if a player, setup sky for only the player, otherwise setup sky for all players + user = *((player_t **)luaL_checkudata(L, 2, META_PLAYER)); + if (!user) // global + P_SetupLevelSky(skynum, true); + else if (P_IsLocalPlayer(user)) + P_SetupLevelSky(skynum, false); return 0; } @@ -1344,6 +1467,19 @@ static int lib_pStartQuake(lua_State *L) return 0; } +static int lib_evCrumbleChain(lua_State *L) +{ + sector_t *sec = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR)); + ffloor_t *rover = *((ffloor_t **)luaL_checkudata(L, 2, META_FFLOOR)); + NOHUD + if (!sec) + return LUA_ErrInvalid(L, "sector_t"); + if (!rover) + return LUA_ErrInvalid(L, "ffloor_t"); + EV_CrumbleChain(sec, rover); + return 0; +} + // R_DEFS //////////// @@ -1421,6 +1557,30 @@ static int lib_rFrame2Char(lua_State *L) return 2; } +// R_SetPlayerSkin technically doesn't exist either, although it's basically just SetPlayerSkin and SetPlayerSkinByNum handled in one place for convenience +static int lib_rSetPlayerSkin(lua_State *L) +{ + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + NOHUD + if (!player) + return LUA_ErrInvalid(L, "player_t"); + if (lua_isnoneornil(L, 2)) + return luaL_error(L, "argument #2 not given (expected number or string)"); + else if (lua_type(L, 2) == LUA_TNUMBER) // skin number + { + INT32 i = luaL_checkinteger(L, 2); + if (i < 0 || i >= MAXSKINS) + return luaL_error(L, "argument #2 cannot exceed MAXSKINS"); + SetPlayerSkinByNum(player-players, i); + } + else // skin name + { + const char *skinname = luaL_checkstring(L, 2); + SetPlayerSkin(player-players, skinname); + } + return 0; +} + // S_SOUND //////////// @@ -1428,6 +1588,7 @@ static int lib_sStartSound(lua_State *L) { const void *origin = NULL; sfxenum_t sound_id = luaL_checkinteger(L, 2); + player_t *player = NULL; NOHUD if (!lua_isnil(L, 1)) { @@ -1435,7 +1596,14 @@ static int lib_sStartSound(lua_State *L) if (!origin) return LUA_ErrInvalid(L, "mobj_t"); } - S_StartSound(origin, sound_id); + if (!lua_isnone(L, 3) && lua_isuserdata(L, 3)) + { + player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) + S_StartSound(origin, sound_id); return 0; } @@ -1444,6 +1612,7 @@ static int lib_sStartSoundAtVolume(lua_State *L) const void *origin = NULL; sfxenum_t sound_id = luaL_checkinteger(L, 2); INT32 volume = (INT32)luaL_checkinteger(L, 3); + player_t *player = NULL; NOHUD if (!lua_isnil(L, 1)) { @@ -1451,6 +1620,13 @@ static int lib_sStartSoundAtVolume(lua_State *L) if (!origin) return LUA_ErrInvalid(L, "mobj_t"); } + if (!lua_isnone(L, 4) && lua_isuserdata(L, 4)) + { + player = *((player_t **)luaL_checkudata(L, 4, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) S_StartSoundAtVolume(origin, sound_id, volume); return 0; } @@ -1469,7 +1645,15 @@ static int lib_sChangeMusic(lua_State *L) { UINT32 music_num = (UINT32)luaL_checkinteger(L, 1); boolean looping = (boolean)lua_opttrueboolean(L, 2); + player_t *player = NULL; NOHUD + if (!lua_isnone(L, 3) && lua_isuserdata(L, 3)) + { + player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) S_ChangeMusic(music_num, looping); return 0; } @@ -1478,15 +1662,33 @@ static int lib_sSpeedMusic(lua_State *L) { fixed_t fixedspeed = (fixed_t)luaL_checkinteger(L, 1); float speed = FIXED_TO_FLOAT(fixedspeed); + player_t *player = NULL; NOHUD - lua_pushboolean(L, S_SpeedMusic(speed)); + if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) + { + player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) + lua_pushboolean(L, S_SpeedMusic(speed)); + else + lua_pushboolean(L, false); return 1; } static int lib_sStopMusic(lua_State *L) { + player_t *player = NULL; NOHUD - S_StopMusic(); + if (!lua_isnone(L, 1) && lua_isuserdata(L, 1)) + { + player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) + S_StopMusic(); return 0; } @@ -1680,7 +1882,10 @@ static luaL_Reg lib[] = { {"P_BossTargetPlayer",lib_pBossTargetPlayer}, {"P_SupermanLook4Players",lib_pSupermanLook4Players}, {"P_SetScale",lib_pSetScale}, + {"P_InsideANonSolidFFloor",lib_pInsideANonSolidFFloor}, {"P_CheckDeathPitCollide",lib_pCheckDeathPitCollide}, + {"P_CheckSolidLava",lib_pCheckSolidLava}, + {"P_CanRunOnWater",lib_pCanRunOnWater}, // p_user {"P_GetPlayerHeight",lib_pGetPlayerHeight}, @@ -1690,13 +1895,18 @@ static luaL_Reg lib[] = { {"P_PlayerInPain",lib_pPlayerInPain}, {"P_DoPlayerPain",lib_pDoPlayerPain}, {"P_ResetPlayer",lib_pResetPlayer}, + {"P_IsObjectInGoop",lib_pIsObjectInGoop}, {"P_IsObjectOnGround",lib_pIsObjectOnGround}, + {"P_InSpaceSector",lib_pInSpaceSector}, + {"P_InQuicksand",lib_pInQuicksand}, {"P_SetObjectMomZ",lib_pSetObjectMomZ}, {"P_RestoreMusic",lib_pRestoreMusic}, + {"P_SpawnShieldOrb",lib_pSpawnShieldOrb}, {"P_SpawnGhostMobj",lib_pSpawnGhostMobj}, {"P_GivePlayerRings",lib_pGivePlayerRings}, {"P_GivePlayerLives",lib_pGivePlayerLives}, {"P_ResetScore",lib_pResetScore}, + {"P_DoJumpShield",lib_pDoJumpShield}, {"P_BlackOw",lib_pBlackOw}, {"P_ElementalFireTrail",lib_pElementalFireTrail}, {"P_DoPlayerExit",lib_pDoPlayerExit}, @@ -1757,6 +1967,7 @@ static luaL_Reg lib[] = { {"P_SetupLevelSky",lib_pSetupLevelSky}, {"P_SetSkyboxMobj",lib_pSetSkyboxMobj}, {"P_StartQuake",lib_pStartQuake}, + {"EV_CrumbleChain",lib_evCrumbleChain}, // r_defs {"R_PointToAngle",lib_rPointToAngle}, @@ -1768,6 +1979,7 @@ static luaL_Reg lib[] = { // r_things (sprite) {"R_Char2Frame",lib_rChar2Frame}, {"R_Frame2Char",lib_rFrame2Char}, + {"R_SetPlayerSkin",lib_rSetPlayerSkin}, // s_sound {"S_StartSound",lib_sStartSound}, diff --git a/src/lua_hook.h b/src/lua_hook.h index a19516cdd..85d00533b 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -33,10 +33,15 @@ enum hook { hook_MobjDeath, hook_BossDeath, hook_MobjRemoved, + hook_JumpSpecial, + hook_AbilitySpecial, + hook_SpinSpecial, + hook_JumpSpinSpecial, hook_BotTiccmd, hook_BotAI, hook_LinedefExecute, hook_PlayerMsg, + hook_DeathMsg, hook_MAX // last hook }; @@ -47,6 +52,7 @@ void LUAh_MapLoad(void); // Hook for map load void LUAh_PlayerJoin(int playernum); // Hook for Got_AddPlayer void LUAh_ThinkFrame(void); // Hook for frame (after mobj and player thinkers) boolean LUAh_MobjHook(mobj_t *mo, enum hook which); +boolean LUAh_PlayerHook(player_t *plr, enum hook which); #define LUAh_MobjSpawn(mo) LUAh_MobjHook(mo, hook_MobjSpawn) // Hook for P_SpawnMobj by mobj type UINT8 LUAh_MobjCollide(mobj_t *thing1, mobj_t *thing2); // Hook for PIT_CheckThing by (thing) mobj type UINT8 LUAh_MobjMoveCollide(mobj_t *thing1, mobj_t *thing2); // Hook for PIT_CheckThing by (tmthing) mobj type @@ -59,9 +65,14 @@ boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source); // Hook for P_KillMobj by mobj type #define LUAh_BossDeath(mo) LUAh_MobjHook(mo, hook_BossDeath) // Hook for A_BossDeath by mobj type #define LUAh_MobjRemoved(mo) LUAh_MobjHook(mo, hook_MobjRemoved) // Hook for P_RemoveMobj by mobj type +#define LUAh_JumpSpecial(player) LUAh_PlayerHook(player, hook_JumpSpecial) // Hook for P_DoJumpStuff (Any-jumping) +#define LUAh_AbilitySpecial(player) LUAh_PlayerHook(player, hook_AbilitySpecial) // Hook for P_DoJumpStuff (Double-jumping) +#define LUAh_SpinSpecial(player) LUAh_PlayerHook(player, hook_SpinSpecial) // Hook for P_DoSpinDash (Spin button effect) +#define LUAh_JumpSpinSpecial(player) LUAh_PlayerHook(player, hook_JumpSpinSpecial) // Hook for P_DoJumpStuff (Spin button effect (mid-air)) boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd); // Hook for B_BuildTiccmd boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd); // Hook for B_BuildTailsTiccmd by skin name boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo); // Hook for linedef executors boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg); // Hook for chat messages +boolean LUAh_DeathMsg(player_t *player, mobj_t *inflictor, mobj_t *source); // Hook for hurt messages #endif diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 608cfa0ba..4e9328e1c 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -44,10 +44,15 @@ const char *const hookNames[hook_MAX+1] = { "MobjDeath", "BossDeath", "MobjRemoved", + "JumpSpecial", + "AbilitySpecial", + "SpinSpecial", + "JumpSpinSpecial", "BotTiccmd", "BotAI", "LinedefExecute", "PlayerMsg", + "HurtMsg", NULL }; @@ -321,6 +326,42 @@ boolean LUAh_MobjHook(mobj_t *mo, enum hook which) return hooked; } +boolean LUAh_PlayerHook(player_t *plr, enum hook which) +{ + boolean hooked = false; + if (!gL || !(hooksAvailable[which/8] & (1<<(which%8)))) + return false; + + // clear the stack (just in case) + lua_pop(gL, -1); + + // hook table + lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); + I_Assert(lua_istable(gL, -1)); + lua_rawgeti(gL, -1, which); + lua_remove(gL, -2); + I_Assert(lua_istable(gL, -1)); + + LUA_PushUserdata(gL, plr, META_PLAYER); + + lua_pushnil(gL); + while (lua_next(gL, -3) != 0) { + lua_pushvalue(gL, -3); // player + if (lua_pcall(gL, 1, 1, 0)) { // pops hook function, player, pushes 1 return result + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); + lua_pop(gL, 1); + continue; + } + if (lua_toboolean(gL, -1)) // if return true, + hooked = true; // override vanilla behavior + lua_pop(gL, 1); // pop return value + } + + lua_pop(gL, -1); + lua_gc(gL, LUA_GCSTEP, 1); + return hooked; +} + // Hook for map change (before load) void LUAh_MapChange(void) { @@ -918,4 +959,45 @@ boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg) return handled; } +// Hook for hurt messages -Red +// The internal name is DeathMsg, but the API name is "HurtMsg". Keep that in mind. (Should this be fixed at some point?) +// @TODO This hook should be fixed to take mobj type at the addHook parameter to compare to inflictor. (I couldn't get this to work without crashing) +boolean LUAh_DeathMsg(player_t *player, mobj_t *inflictor, mobj_t *source) +{ + boolean handled = false; + + if (!gL || !(hooksAvailable[hook_DeathMsg/8] & (1<<(hook_DeathMsg%8)))) + return false; + + lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); + I_Assert(lua_istable(gL, -1)); + lua_rawgeti(gL, -1, hook_DeathMsg); + lua_remove(gL, -2); + I_Assert(lua_istable(gL, -1)); + + LUA_PushUserdata(gL, player, META_PLAYER); // Player + LUA_PushUserdata(gL, inflictor, META_MOBJ); // Inflictor + LUA_PushUserdata(gL, source, META_MOBJ); // Source + + lua_pushnil(gL); + + while (lua_next(gL, -5)) { + lua_pushvalue(gL, -5); // player + lua_pushvalue(gL, -5); // inflictor + lua_pushvalue(gL, -5); // source + if (lua_pcall(gL, 3, 1, 0)) { + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); + lua_pop(gL, 1); + continue; + } + if (lua_toboolean(gL, -1)) + handled = true; + lua_pop(gL, 1); // pop return value + } + lua_pop(gL, 3); // pop arguments and mobjtype table + + lua_gc(gL, LUA_GCSTEP, 1); + return handled; +} + #endif diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 176b816ec..f388a1ff4 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -15,6 +15,7 @@ #include "r_defs.h" #include "st_stuff.h" // hudinfo[] #include "g_game.h" +#include "p_local.h" // camera_t #include "v_video.h" #include "w_wad.h" #include "z_zone.h" @@ -23,6 +24,8 @@ #include "lua_libs.h" #include "lua_hud.h" +#define HUDONLY if (!hud_running) return luaL_error(L, "HUD rendering code should not be called outside of rendering hooks!"); + boolean hud_running = false; static UINT8 hud_enabled[(hud_MAX/8)+1]; @@ -85,17 +88,79 @@ static const char *const hudhook_opt[] = { "scores", NULL}; +// alignment types for v.drawString enum align { align_left = 0, align_center, align_right, - align_fixed + align_fixed, + align_small, + align_smallright, + align_thin, + align_thinright }; static const char *const align_opt[] = { "left", "center", "right", "fixed", + "small", + "small-right", + "thin", + "thin-right", + NULL}; + +// width types for v.stringWidth +enum widtht { + widtht_normal = 0, + widtht_small, + widtht_thin +}; +static const char *const widtht_opt[] = { + "normal", + "small", + "thin", + NULL}; + +enum cameraf { + camera_chase = 0, + camera_aiming, + camera_viewheight, + camera_startangle, + camera_x, + camera_y, + camera_z, + camera_angle, + camera_subsector, + camera_floorz, + camera_ceilingz, + camera_radius, + camera_height, + camera_relativex, + camera_momx, + camera_momy, + camera_momz +}; + + +static const char *const camera_opt[] = { + "chase", + "aiming", + "viewheight", + "startangle", + "x", + "y", + "z", + "angle", + "subsector", + "floorz", + "ceilingz", + "radius", + "height", + "relativex", + "momx", + "momy", + "momz", NULL}; static int lib_getHudInfo(lua_State *L) @@ -193,24 +258,85 @@ static int patch_set(lua_State *L) return luaL_error(L, LUA_QL("patch_t") " struct cannot be edited by Lua."); } +static int camera_get(lua_State *L) +{ + camera_t *cam = *((camera_t **)luaL_checkudata(L, 1, META_CAMERA)); + enum cameraf field = luaL_checkoption(L, 2, NULL, camera_opt); + + // cameras should always be valid unless I'm a nutter + I_Assert(cam != NULL); + + switch (field) + { + case camera_chase: + lua_pushboolean(L, cam->chase); + break; + case camera_aiming: + lua_pushinteger(L, cam->aiming); + break; + case camera_viewheight: + lua_pushinteger(L, cam->viewheight); + break; + case camera_startangle: + lua_pushinteger(L, cam->startangle); + break; + case camera_x: + lua_pushinteger(L, cam->x); + break; + case camera_y: + lua_pushinteger(L, cam->y); + break; + case camera_z: + lua_pushinteger(L, cam->z); + break; + case camera_angle: + lua_pushinteger(L, cam->angle); + break; + case camera_subsector: + LUA_PushUserdata(L, cam->subsector, META_SUBSECTOR); + break; + case camera_floorz: + lua_pushinteger(L, cam->floorz); + break; + case camera_ceilingz: + lua_pushinteger(L, cam->ceilingz); + break; + case camera_radius: + lua_pushinteger(L, cam->radius); + break; + case camera_height: + lua_pushinteger(L, cam->height); + break; + case camera_relativex: + lua_pushinteger(L, cam->relativex); + break; + case camera_momx: + lua_pushinteger(L, cam->momx); + break; + case camera_momy: + lua_pushinteger(L, cam->momy); + break; + case camera_momz: + lua_pushinteger(L, cam->momz); + break; + } + return 1; +} + // // lib_draw // static int libd_patchExists(lua_State *L) { - if (!hud_running) - return luaL_error(L, "HUD rendering code should not be called outside of rendering hooks!"); - + HUDONLY lua_pushboolean(L, W_LumpExists(luaL_checkstring(L, 1))); return 1; } static int libd_cachePatch(lua_State *L) { - if (!hud_running) - return luaL_error(L, "HUD rendering code should not be called outside of rendering hooks!"); - + HUDONLY LUA_PushUserdata(L, W_CachePatchName(luaL_checkstring(L, 1), PU_STATIC), META_PATCH); return 1; } @@ -221,9 +347,7 @@ static int libd_draw(lua_State *L) patch_t *patch; const UINT8 *colormap = NULL; - if (!hud_running) - return luaL_error(L, "HUD rendering code should not be called outside of rendering hooks!"); - + HUDONLY x = luaL_checkinteger(L, 1); y = luaL_checkinteger(L, 2); patch = *((patch_t **)luaL_checkudata(L, 3, META_PATCH)); @@ -244,9 +368,7 @@ static int libd_drawScaled(lua_State *L) patch_t *patch; const UINT8 *colormap = NULL; - if (!hud_running) - return luaL_error(L, "HUD rendering code should not be called outside of rendering hooks!"); - + HUDONLY x = luaL_checkinteger(L, 1); y = luaL_checkinteger(L, 2); scale = luaL_checkinteger(L, 3); @@ -264,9 +386,7 @@ static int libd_drawScaled(lua_State *L) static int libd_drawNum(lua_State *L) { INT32 x, y, flags, num; - if (!hud_running) - return luaL_error(L, "HUD rendering code should not be called outside of rendering hooks!"); - + HUDONLY x = luaL_checkinteger(L, 1); y = luaL_checkinteger(L, 2); num = luaL_checkinteger(L, 3); @@ -280,9 +400,7 @@ static int libd_drawNum(lua_State *L) static int libd_drawPaddedNum(lua_State *L) { INT32 x, y, flags, num, digits; - if (!hud_running) - return luaL_error(L, "HUD rendering code should not be called outside of rendering hooks!"); - + HUDONLY x = luaL_checkinteger(L, 1); y = luaL_checkinteger(L, 2); num = abs(luaL_checkinteger(L, 3)); @@ -302,9 +420,7 @@ static int libd_drawFill(lua_State *L) INT32 h = luaL_optinteger(L, 4, BASEVIDHEIGHT); INT32 c = luaL_optinteger(L, 5, 31); - if (!hud_running) - return luaL_error(L, "HUD rendering code should not be called outside of rendering hooks!"); - + HUDONLY V_DrawFill(x, y, w, h, c); return 0; } @@ -319,11 +435,10 @@ static int libd_drawString(lua_State *L) flags &= ~V_PARAMMASK; // Don't let crashes happen. - if (!hud_running) - return luaL_error(L, "HUD rendering code should not be called outside of rendering hooks!"); - + HUDONLY switch(align) { + // hu_font case align_left: V_DrawString(x, y, flags, str); break; @@ -336,6 +451,20 @@ static int libd_drawString(lua_State *L) case align_fixed: V_DrawStringAtFixed(x, y, flags, str); break; + // hu_font, 0.5x scale + case align_small: + V_DrawSmallString(x, y, flags, str); + break; + case align_smallright: + V_DrawRightAlignedSmallString(x, y, flags, str); + break; + // tny_font + case align_thin: + V_DrawThinString(x, y, flags, str); + break; + case align_thinright: + V_DrawRightAlignedThinString(x, y, flags, str); + break; } return 0; } @@ -344,11 +473,21 @@ static int libd_stringWidth(lua_State *L) { const char *str = luaL_checkstring(L, 1); INT32 flags = luaL_optinteger(L, 2, V_ALLOWLOWERCASE); + enum widtht widtht = luaL_checkoption(L, 3, "normal", widtht_opt); - if (!hud_running) - return luaL_error(L, "HUD rendering code should not be called outside of rendering hooks!"); - - lua_pushinteger(L, V_StringWidth(str, flags)); + HUDONLY + switch(widtht) + { + case widtht_normal: // hu_font + lua_pushinteger(L, V_StringWidth(str, flags)); + break; + case widtht_small: // hu_font, 0.5x scale + lua_pushinteger(L, V_SmallStringWidth(str, flags)); + break; + case widtht_thin: // tny_font + lua_pushinteger(L, V_ThinStringWidth(str, flags)); + break; + } return 1; } @@ -462,6 +601,11 @@ int LUA_HudLib(lua_State *L) lua_setfield(L, -2, "__newindex"); lua_pop(L,1); + luaL_newmetatable(L, META_CAMERA); + lua_pushcfunction(L, camera_get); + lua_setfield(L, -2, "__index"); + lua_pop(L,1); + luaL_register(L, "hud", lib_hud); return 0; } @@ -474,7 +618,7 @@ boolean LUA_HudEnabled(enum hud option) } // Hook for HUD rendering -void LUAh_GameHUD(player_t *stplyr) +void LUAh_GameHUD(player_t *stplayr) { if (!gL || !(hudAvailable & (1< end'."); + + if (!lua_isnil(L, 1)) + state = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + else + return 0; // no thinglist to iterate through sorry! + + lua_settop(L, 2); + lua_remove(L, 1); // remove state now. + + if (!lua_isnil(L, 1)) + { + thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + thing = thing->snext; + } + else + thing = state; // state is used as the "start" of the thinglist + + if (thing) + { + LUA_PushUserdata(L, thing, META_MOBJ); + return 1; + } + return 0; +} + +// iterates through the ffloors list in a sector! +static int lib_iterateSectorFFloors(lua_State *L) +{ + ffloor_t *state = NULL; + ffloor_t *ffloor = NULL; + + if (lua_gettop(L) < 2) + return luaL_error(L, "Don't call sector.ffloors() directly, use it as 'for rover in sector.ffloors do end'."); + + if (!lua_isnil(L, 1)) + state = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR)); + else + return 0; // no ffloors to iterate through sorry! + + lua_settop(L, 2); + lua_remove(L, 1); // remove state now. + + if (!lua_isnil(L, 1)) + { + ffloor = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR)); + ffloor = ffloor->next; + } + else + ffloor = state; // state is used as the "start" of the ffloor list + + if (ffloor) + { + LUA_PushUserdata(L, ffloor, META_FFLOOR); + return 1; + } + return 0; +} + +static int sector_iterate(lua_State *L) +{ + lua_pushvalue(L, lua_upvalueindex(1)); // iterator function, or the "generator" + lua_pushvalue(L, lua_upvalueindex(2)); // state (used as the "start" of the list for our purposes + lua_pushnil(L); // initial value (unused) + return 3; +} + static int sector_get(lua_State *L) { sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR)); - int field = luaL_checkoption(L, 2, sector_opt[0], sector_opt); + enum sector_e field = luaL_checkoption(L, 2, sector_opt[0], sector_opt); if (!sector) { - if (field == 0) { + if (field == sector_valid) { lua_pushboolean(L, 0); return 1; } @@ -100,16 +278,16 @@ static int sector_get(lua_State *L) switch(field) { - case 0: // valid + case sector_valid: // valid lua_pushboolean(L, 1); return 1; - case 1: + case sector_floorheight: lua_pushinteger(L, sector->floorheight); return 1; - case 2: + case sector_ceilingheight: lua_pushinteger(L, sector->ceilingheight); return 1; - case 3: { // floorpic + case sector_floorpic: { // floorpic levelflat_t *levelflat; INT16 i; for (i = 0, levelflat = levelflats; i != sector->floorpic; i++, levelflat++) @@ -117,7 +295,7 @@ static int sector_get(lua_State *L) lua_pushlstring(L, levelflat->name, 8); return 1; } - case 4: { // ceilingpic + case sector_ceilingpic: { // ceilingpic levelflat_t *levelflat; INT16 i; for (i = 0, levelflat = levelflats; i != sector->ceilingpic; i++, levelflat++) @@ -125,15 +303,35 @@ static int sector_get(lua_State *L) lua_pushlstring(L, levelflat->name, 8); return 1; } - case 5: + case sector_lightlevel: lua_pushinteger(L, sector->lightlevel); return 1; - case 6: + case sector_special: lua_pushinteger(L, sector->special); return 1; - case 7: + case sector_tag: lua_pushinteger(L, sector->tag); return 1; + case sector_thinglist: // thinglist + lua_pushcfunction(L, lib_iterateSectorThinglist); + LUA_PushUserdata(L, sector->thinglist, META_MOBJ); + lua_pushcclosure(L, sector_iterate, 2); // push lib_iterateSectorThinglist and sector->thinglist as upvalues for the function + return 1; + case sector_heightsec: // heightsec - fake floor heights + if (sector->heightsec < 0) + return 0; + LUA_PushUserdata(L, §ors[sector->heightsec], META_SECTOR); + return 1; + case sector_camsec: // camsec - camera clipping heights + if (sector->camsec < 0) + return 0; + LUA_PushUserdata(L, §ors[sector->camsec], META_SECTOR); + return 1; + case sector_ffloors: // ffloors + lua_pushcfunction(L, lib_iterateSectorFFloors); + LUA_PushUserdata(L, sector->ffloors, META_FFLOOR); + lua_pushcclosure(L, sector_iterate, 2); // push lib_iterateFFloors and sector->ffloors as upvalues for the function + return 1; } return 0; } @@ -181,7 +379,7 @@ static INT32 P_AddLevelFlatRuntime(const char *flatname) static int sector_set(lua_State *L) { sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR)); - int field = luaL_checkoption(L, 2, sector_opt[0], sector_opt); + enum sector_e field = luaL_checkoption(L, 2, sector_opt[0], sector_opt); if (!sector) return luaL_error(L, "accessed sector_t doesn't exist anymore."); @@ -191,10 +389,14 @@ static int sector_set(lua_State *L) switch(field) { - case 0: // valid + case sector_valid: // valid + case sector_thinglist: // thinglist + case sector_heightsec: // heightsec + case sector_camsec: // camsec + case sector_ffloors: // ffloors default: return luaL_error(L, "sector_t field " LUA_QS " cannot be set.", sector_opt[field]); - case 1: { // floorheight + case sector_floorheight: { // floorheight boolean flag; fixed_t lastpos = sector->floorheight; sector->floorheight = (fixed_t)luaL_checkinteger(L, 3); @@ -206,7 +408,7 @@ static int sector_set(lua_State *L) } break; } - case 2: { // ceilingheight + case sector_ceilingheight: { // ceilingheight boolean flag; fixed_t lastpos = sector->ceilingheight; sector->ceilingheight = (fixed_t)luaL_checkinteger(L, 3); @@ -218,19 +420,19 @@ static int sector_set(lua_State *L) } break; } - case 3: + case sector_floorpic: sector->floorpic = P_AddLevelFlatRuntime(luaL_checkstring(L, 3)); break; - case 4: + case sector_ceilingpic: sector->ceilingpic = P_AddLevelFlatRuntime(luaL_checkstring(L, 3)); break; - case 5: + case sector_lightlevel: sector->lightlevel = (INT16)luaL_checkinteger(L, 3); break; - case 6: + case sector_special: sector->special = (INT16)luaL_checkinteger(L, 3); break; - case 7: + case sector_tag: P_ChangeSectorTag((UINT32)(sector - sectors), (INT16)luaL_checkinteger(L, 3)); break; } @@ -247,11 +449,11 @@ static int sector_num(lua_State *L) static int subsector_get(lua_State *L) { subsector_t *subsector = *((subsector_t **)luaL_checkudata(L, 1, META_SUBSECTOR)); - int field = luaL_checkoption(L, 2, subsector_opt[0], subsector_opt); + enum subsector_e field = luaL_checkoption(L, 2, subsector_opt[0], subsector_opt); if (!subsector) { - if (field == 0) { + if (field == subsector_valid) { lua_pushboolean(L, 0); return 1; } @@ -260,19 +462,19 @@ static int subsector_get(lua_State *L) switch(field) { - case 0: // valid + case subsector_valid: // valid lua_pushboolean(L, 1); return 1; - case 1: + case subsector_sector: LUA_PushUserdata(L, subsector->sector, META_SECTOR); return 1; - case 2: + case subsector_numlines: lua_pushinteger(L, subsector->numlines); return 1; - case 3: + case subsector_firstline: lua_pushinteger(L, subsector->firstline); return 1; - case 4: + case subsector_validcount: lua_pushinteger(L, subsector->validcount); return 1; } @@ -289,11 +491,11 @@ static int subsector_num(lua_State *L) static int line_get(lua_State *L) { line_t *line = *((line_t **)luaL_checkudata(L, 1, META_LINE)); - int field = luaL_checkoption(L, 2, line_opt[0], line_opt); + enum line_e field = luaL_checkoption(L, 2, line_opt[0], line_opt); if (!line) { - if (field == 0) { + if (field == line_valid) { lua_pushboolean(L, 0); return 1; } @@ -302,43 +504,43 @@ static int line_get(lua_State *L) switch(field) { - case 0: // valid + case line_valid: // valid lua_pushboolean(L, 1); return 1; - case 1: + case line_v1: LUA_PushUserdata(L, line->v1, META_VERTEX); return 1; - case 2: + case line_v2: LUA_PushUserdata(L, line->v2, META_VERTEX); return 1; - case 3: + case line_dx: lua_pushinteger(L, line->dx); return 1; - case 4: + case line_dy: lua_pushinteger(L, line->dy); return 1; - case 5: + case line_flags: lua_pushinteger(L, line->flags); return 1; - case 6: + case line_special: lua_pushinteger(L, line->special); return 1; - case 7: + case line_tag: lua_pushinteger(L, line->tag); return 1; - case 8: + case line_sidenum: LUA_PushUserdata(L, line->sidenum, META_SIDENUM); return 1; - case 9: // frontside + case line_frontside: // frontside LUA_PushUserdata(L, &sides[line->sidenum[0]], META_SIDE); return 1; - case 10: // backside + case line_backside: // backside if (line->sidenum[1] == 0xffff) return 0; LUA_PushUserdata(L, &sides[line->sidenum[1]], META_SIDE); return 1; - case 11: - switch(lines->slopetype) + case line_slopetype: + switch(line->slopetype) { case ST_HORIZONTAL: lua_pushliteral(L, "horizontal"); @@ -354,22 +556,22 @@ static int line_get(lua_State *L) break; } return 1; - case 12: + case line_frontsector: LUA_PushUserdata(L, line->frontsector, META_SECTOR); return 1; - case 13: + case line_backsector: LUA_PushUserdata(L, line->backsector, META_SECTOR); return 1; - case 14: + case line_validcount: lua_pushinteger(L, line->validcount); return 1; - case 15: + case line_firsttag: lua_pushinteger(L, line->firsttag); return 1; - case 16: + case line_nexttag: lua_pushinteger(L, line->nexttag); return 1; - case 17: + case line_text: lua_pushstring(L, line->text); return 1; } @@ -414,11 +616,11 @@ static int sidenum_get(lua_State *L) static int side_get(lua_State *L) { side_t *side = *((side_t **)luaL_checkudata(L, 1, META_SIDE)); - int field = luaL_checkoption(L, 2, side_opt[0], side_opt); + enum side_e field = luaL_checkoption(L, 2, side_opt[0], side_opt); if (!side) { - if (field == 0) { + if (field == side_valid) { lua_pushboolean(L, 0); return 1; } @@ -427,34 +629,34 @@ static int side_get(lua_State *L) switch(field) { - case 0: // valid + case side_valid: // valid lua_pushboolean(L, 1); return 1; - case 1: + case side_textureoffset: lua_pushinteger(L, side->textureoffset); return 1; - case 2: + case side_rowoffset: lua_pushinteger(L, side->rowoffset); return 1; - case 3: + case side_toptexture: lua_pushinteger(L, side->toptexture); return 1; - case 4: + case side_bottomtexture: lua_pushinteger(L, side->bottomtexture); return 1; - case 5: + case side_midtexture: lua_pushinteger(L, side->midtexture); return 1; - case 6: + case side_sector: LUA_PushUserdata(L, side->sector, META_SECTOR); return 1; - case 7: + case side_special: lua_pushinteger(L, side->special); return 1; - case 8: + case side_repeatcnt: lua_pushinteger(L, side->repeatcnt); return 1; - case 9: + case side_text: lua_pushstring(L, side->text); return 1; } @@ -471,11 +673,11 @@ static int side_num(lua_State *L) static int vertex_get(lua_State *L) { vertex_t *vertex = *((vertex_t **)luaL_checkudata(L, 1, META_VERTEX)); - int field = luaL_checkoption(L, 2, vertex_opt[0], vertex_opt); + enum vertex_e field = luaL_checkoption(L, 2, vertex_opt[0], vertex_opt); if (!vertex) { - if (field == 0) { + if (field == vertex_valid) { lua_pushboolean(L, 0); return 1; } @@ -484,16 +686,16 @@ static int vertex_get(lua_State *L) switch(field) { - case 0: // valid + case vertex_valid: // valid lua_pushboolean(L, 1); return 1; - case 1: + case vertex_x: lua_pushinteger(L, vertex->x); return 1; - case 2: + case vertex_y: lua_pushinteger(L, vertex->y); return 1; - case 3: + case vertex_z: lua_pushinteger(L, vertex->z); return 1; } @@ -737,6 +939,248 @@ static int lib_numvertexes(lua_State *L) return 1; } +static int ffloor_get(lua_State *L) +{ + ffloor_t *ffloor = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR)); + enum ffloor_e field = luaL_checkoption(L, 2, ffloor_opt[0], ffloor_opt); + + if (!ffloor) + { + if (field == ffloor_valid) { + lua_pushboolean(L, 0); + return 1; + } + return luaL_error(L, "accessed ffloor_t doesn't exist anymore."); + } + + switch(field) + { + case ffloor_valid: // valid + lua_pushboolean(L, 1); + return 1; + case ffloor_topheight: + lua_pushinteger(L, *ffloor->topheight); + return 1; + case ffloor_toppic: { // toppic + levelflat_t *levelflat; + INT16 i; + for (i = 0, levelflat = levelflats; i != *ffloor->toppic; i++, levelflat++) + ; + lua_pushlstring(L, levelflat->name, 8); + return 1; + } + case ffloor_toplightlevel: + lua_pushinteger(L, *ffloor->toplightlevel); + return 1; + case ffloor_bottomheight: + lua_pushinteger(L, *ffloor->bottomheight); + return 1; + case ffloor_bottompic: { // bottompic + levelflat_t *levelflat; + INT16 i; + for (i = 0, levelflat = levelflats; i != *ffloor->bottompic; i++, levelflat++) + ; + lua_pushlstring(L, levelflat->name, 8); + return 1; + } + case ffloor_sector: + LUA_PushUserdata(L, §ors[ffloor->secnum], META_SECTOR); + return 1; + case ffloor_flags: + lua_pushinteger(L, ffloor->flags); + return 1; + case ffloor_master: + LUA_PushUserdata(L, ffloor->master, META_LINE); + return 1; + case ffloor_target: + LUA_PushUserdata(L, ffloor->target, META_SECTOR); + return 1; + case ffloor_next: + LUA_PushUserdata(L, ffloor->next, META_FFLOOR); + return 1; + case ffloor_prev: + LUA_PushUserdata(L, ffloor->prev, META_FFLOOR); + return 1; + case ffloor_alpha: + lua_pushinteger(L, ffloor->alpha); + return 1; + } + return 0; +} + +static int ffloor_set(lua_State *L) +{ + ffloor_t *ffloor = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR)); + enum ffloor_e field = luaL_checkoption(L, 2, ffloor_opt[0], ffloor_opt); + + if (!ffloor) + return luaL_error(L, "accessed ffloor_t doesn't exist anymore."); + + if (hud_running) + return luaL_error(L, "Do not alter ffloor_t in HUD rendering code!"); + + switch(field) + { + case ffloor_valid: // valid + case ffloor_sector: // sector + case ffloor_master: // master + case ffloor_target: // target + case ffloor_next: // next + case ffloor_prev: // prev + default: + return luaL_error(L, "ffloor_t field " LUA_QS " cannot be set.", ffloor_opt[field]); + case ffloor_topheight: { // topheight + boolean flag; + fixed_t lastpos = *ffloor->topheight; + sector_t *sector = §ors[ffloor->secnum]; + sector->floorheight = (fixed_t)luaL_checkinteger(L, 3); + flag = P_CheckSector(sector, true); + if (flag && sector->numattached) + { + *ffloor->topheight = lastpos; + P_CheckSector(sector, true); + } + break; + } + case ffloor_toppic: + *ffloor->toppic = P_AddLevelFlatRuntime(luaL_checkstring(L, 3)); + break; + case ffloor_toplightlevel: + *ffloor->toplightlevel = (INT16)luaL_checkinteger(L, 3); + break; + case ffloor_bottomheight: { // bottomheight + boolean flag; + fixed_t lastpos = *ffloor->bottomheight; + sector_t *sector = §ors[ffloor->secnum]; + sector->ceilingheight = (fixed_t)luaL_checkinteger(L, 3); + flag = P_CheckSector(sector, true); + if (flag && sector->numattached) + { + *ffloor->bottomheight = lastpos; + P_CheckSector(sector, true); + } + break; + } + case ffloor_bottompic: + *ffloor->bottompic = P_AddLevelFlatRuntime(luaL_checkstring(L, 3)); + break; + case ffloor_flags: + ffloor->flags = luaL_checkinteger(L, 3); + break; + case ffloor_alpha: + ffloor->alpha = (INT32)luaL_checkinteger(L, 3); + break; + } + return 0; +} + +static int lib_getMapheaderinfo(lua_State *L) +{ + // i -> mapheaderinfo[i-1] + + //int field; + lua_settop(L, 2); + lua_remove(L, 1); // dummy userdata table is unused. + if (lua_isnumber(L, 1)) + { + size_t i = lua_tointeger(L, 1)-1; + if (i >= NUMMAPS) + return 0; + LUA_PushUserdata(L, mapheaderinfo[i], META_MAPHEADER); + //CONS_Printf(mapheaderinfo[i]->lvlttl); + return 1; + }/* + field = luaL_checkoption(L, 1, NULL, array_opt); + switch(field) + { + case 0: // iterate + lua_pushcfunction(L, lib_iterateSubsectors); + return 1; + }*/ + return 0; +} + +static int lib_nummapheaders(lua_State *L) +{ + lua_pushinteger(L, NUMMAPS); + return 1; +} + +static int mapheaderinfo_get(lua_State *L) +{ + mapheader_t *header = *((mapheader_t **)luaL_checkudata(L, 1, META_MAPHEADER)); + const char *field = luaL_checkstring(L, 2); + //INT16 i; + if (fastcmp(field,"lvlttl")) { + //for (i = 0; i < 21; i++) + // if (!header->lvlttl[i]) + // break; + lua_pushlstring(L, header->lvlttl, 21); + } else if (fastcmp(field,"subttl")) + lua_pushlstring(L, header->subttl, 32); + else if (fastcmp(field,"actnum")) + lua_pushinteger(L, header->actnum); + else if (fastcmp(field,"typeoflevel")) + lua_pushinteger(L, header->typeoflevel); + else if (fastcmp(field,"nextlevel")) + lua_pushinteger(L, header->nextlevel); + else if (fastcmp(field,"musicslot")) + lua_pushinteger(L, header->musicslot); + else if (fastcmp(field,"musicslottrack")) + lua_pushinteger(L, header->musicslottrack); + else if (fastcmp(field,"forcecharacter")) + lua_pushlstring(L, header->forcecharacter, 16); + else if (fastcmp(field,"weather")) + lua_pushinteger(L, header->weather); + else if (fastcmp(field,"skynum")) + lua_pushinteger(L, header->skynum); + else if (fastcmp(field,"skybox_scalex")) + lua_pushinteger(L, header->skybox_scalex); + else if (fastcmp(field,"skybox_scaley")) + lua_pushinteger(L, header->skybox_scaley); + else if (fastcmp(field,"skybox_scalez")) + lua_pushinteger(L, header->skybox_scalez); + else if (fastcmp(field,"interscreen")) + lua_pushlstring(L, header->interscreen, 8); + else if (fastcmp(field,"runsoc")) + lua_pushlstring(L, header->runsoc, 32); + else if (fastcmp(field,"scriptname")) + lua_pushlstring(L, header->scriptname, 32); + else if (fastcmp(field,"precutscenenum")) + lua_pushinteger(L, header->precutscenenum); + else if (fastcmp(field,"cutscenenum")) + lua_pushinteger(L, header->cutscenenum); + else if (fastcmp(field,"countdown")) + lua_pushinteger(L, header->countdown); + else if (fastcmp(field,"palette")) + lua_pushinteger(L, header->palette); + else if (fastcmp(field,"numlaps")) + lua_pushinteger(L, header->numlaps); + else if (fastcmp(field,"unlockrequired")) + lua_pushinteger(L, header->unlockrequired); + else if (fastcmp(field,"levelselect")) + lua_pushinteger(L, header->levelselect); + else if (fastcmp(field,"bonustype")) + lua_pushinteger(L, header->bonustype); + else if (fastcmp(field,"levelflags")) + lua_pushinteger(L, header->levelflags); + else if (fastcmp(field,"menuflags")) + lua_pushinteger(L, header->menuflags); + // TODO add support for reading numGradedMares and grades + else { + // Read custom vars now + // (note: don't include the "LUA." in your lua scripts!) + UINT8 i = 0; + for (;i < header->numCustomOptions && !fastcmp(field, header->customopts[i].option); ++i); + + if(i < header->numCustomOptions) + lua_pushlstring(L, header->customopts[i].value, 255); + else + lua_pushnil(L); + } + return 1; +} + int LUA_MapLib(lua_State *L) { luaL_newmetatable(L, META_SECTOR); @@ -787,6 +1231,22 @@ int LUA_MapLib(lua_State *L) lua_setfield(L, -2, "__len"); lua_pop(L, 1); + luaL_newmetatable(L, META_FFLOOR); + lua_pushcfunction(L, ffloor_get); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, ffloor_set); + lua_setfield(L, -2, "__newindex"); + lua_pop(L, 1); + + luaL_newmetatable(L, META_MAPHEADER); + lua_pushcfunction(L, mapheaderinfo_get); + lua_setfield(L, -2, "__index"); + + //lua_pushcfunction(L, mapheaderinfo_num); + //lua_setfield(L, -2, "__len"); + lua_pop(L, 1); + lua_newuserdata(L, 0); lua_createtable(L, 0, 2); lua_pushcfunction(L, lib_getSector); @@ -836,6 +1296,16 @@ int LUA_MapLib(lua_State *L) lua_setfield(L, -2, "__len"); lua_setmetatable(L, -2); lua_setglobal(L, "vertexes"); + + lua_newuserdata(L, 0); + lua_createtable(L, 0, 2); + lua_pushcfunction(L, lib_getMapheaderinfo); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, lib_nummapheaders); + lua_setfield(L, -2, "__len"); + lua_setmetatable(L, -2); + lua_setglobal(L, "mapheaderinfo"); return 0; } diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 6fb70ccfc..f455edf1f 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -395,7 +395,7 @@ static int mobj_set(lua_State *L) return UNIMPLEMENTED; case mobj_angle: mo->angle = (angle_t)luaL_checkinteger(L, 3); - if (mo->player == &players[displayplayer]) + if (mo->player == &players[consoleplayer]) localangle = mo->angle; else if (mo->player == &players[secondarydisplayplayer]) localangle2 = mo->angle; diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 20d9fb620..2686aed97 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -267,7 +267,7 @@ static int player_get(lua_State *L) else if (fastcmp(field,"drilldelay")) lua_pushinteger(L, plr->drilldelay); else if (fastcmp(field,"bonustime")) - lua_pushinteger(L, plr->bonustime); + lua_pushboolean(L, plr->bonustime); else if (fastcmp(field,"capsule")) LUA_PushUserdata(L, plr->capsule, META_MOBJ); else if (fastcmp(field,"mare")) @@ -345,14 +345,9 @@ static int player_set(lua_State *L) return luaL_error(L, "Do not alter player_t in HUD rendering code!"); if (fastcmp(field,"mo")) { - if (!lua_isnil(L, 3)) - { - plr->mo->player = NULL; - plr->mo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); - plr->mo->player = plr; - } - else - return luaL_error(L, "player.mo should not be nil!"); + mobj_t *newmo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); + plr->mo->player = NULL; // remove player pointer from old mobj + (newmo->player = plr)->mo = newmo; // set player pointer for new mobj, and set new mobj as the player's mobj } else if (fastcmp(field,"cmd")) return NOSET; @@ -368,7 +363,7 @@ static int player_set(lua_State *L) plr->bob = (fixed_t)luaL_checkinteger(L, 3); else if (fastcmp(field,"aiming")) { plr->aiming = (angle_t)luaL_checkinteger(L, 3); - if (plr == &players[displayplayer]) + if (plr == &players[consoleplayer]) localaiming = plr->aiming; else if (plr == &players[secondarydisplayplayer]) localaiming2 = plr->aiming; @@ -392,7 +387,7 @@ static int player_set(lua_State *L) else if (fastcmp(field,"flashpal")) plr->flashpal = (UINT16)luaL_checkinteger(L, 3); else if (fastcmp(field,"skincolor")) - plr->skincolor = (UINT8)luaL_checkinteger(L, 3); + plr->skincolor = ((UINT8)luaL_checkinteger(L, 3)) % MAXSKINCOLORS; else if (fastcmp(field,"score")) plr->score = (UINT32)luaL_checkinteger(L, 3); else if (fastcmp(field,"dashspeed")) @@ -623,7 +618,7 @@ static int power_get(lua_State *L) { UINT16 *powers = *((UINT16 **)luaL_checkudata(L, 1, META_POWERS)); powertype_t p = luaL_checkinteger(L, 2); - if (p > NUMPOWERS) + if (p >= NUMPOWERS) return luaL_error(L, LUA_QL("powertype_t") " cannot be %u", p); lua_pushinteger(L, powers[p]); return 1; @@ -635,7 +630,7 @@ static int power_set(lua_State *L) UINT16 *powers = *((UINT16 **)luaL_checkudata(L, 1, META_POWERS)); powertype_t p = luaL_checkinteger(L, 2); UINT16 i = (UINT16)luaL_checkinteger(L, 3); - if (p > NUMPOWERS) + if (p >= NUMPOWERS) return luaL_error(L, LUA_QL("powertype_t") " cannot be %u", p); if (hud_running) return luaL_error(L, "Do not alter player_t in HUD rendering code!"); diff --git a/src/lua_script.c b/src/lua_script.c index 4f37c0903..b50bd0977 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -30,6 +30,8 @@ #include "lua_libs.h" #include "lua_hook.h" +#include "doomstat.h" + lua_State *gL = NULL; // List of internal libraries to load from SRB2 @@ -453,6 +455,7 @@ enum ARCH_SIDE, ARCH_SUBSECTOR, ARCH_SECTOR, + ARCH_MAPHEADER, ARCH_TEND=0xFF, }; @@ -471,6 +474,7 @@ static const struct { {META_SIDE, ARCH_SIDE}, {META_SUBSECTOR,ARCH_SUBSECTOR}, {META_SECTOR, ARCH_SECTOR}, + {META_MAPHEADER, ARCH_MAPHEADER}, {NULL, ARCH_NULL} }; @@ -665,6 +669,17 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) } break; } + case ARCH_MAPHEADER: + { + mapheader_t *header = *((mapheader_t **)lua_touserdata(gL, myindex)); + if (!header) + WRITEUINT8(save_p, ARCH_NULL); + else { + WRITEUINT8(save_p, ARCH_MAPHEADER); + WRITEUINT16(save_p, header - *mapheaderinfo); + } + break; + } default: WRITEUINT8(save_p, ARCH_NULL); return 2; @@ -835,6 +850,9 @@ static UINT8 UnArchiveValue(int TABLESINDEX) case ARCH_SECTOR: LUA_PushUserdata(gL, §ors[READUINT16(save_p)], META_SECTOR); break; + case ARCH_MAPHEADER: + LUA_PushUserdata(gL, §ors[READUINT16(save_p)], META_MAPHEADER); + break; case ARCH_TEND: return 1; } diff --git a/src/lua_skinlib.c b/src/lua_skinlib.c index b26036308..f797f30d6 100644 --- a/src/lua_skinlib.c +++ b/src/lua_skinlib.c @@ -14,6 +14,7 @@ #ifdef HAVE_BLUA #include "fastcmp.h" #include "r_things.h" +#include "sounds.h" #include "lua_script.h" #include "lua_libs.h" @@ -182,7 +183,8 @@ static int skin_get(lua_State *L) lua_pushinteger(L, skin->highresscale); break; case skin_soundsid: - return UNIMPLEMENTED; + LUA_PushUserdata(L, skin->soundsid, META_SOUNDSID); + break; } return 1; } @@ -275,6 +277,24 @@ static int lib_numSkins(lua_State *L) return 1; } +// soundsid, i -> soundsid[i] +static int soundsid_get(lua_State *L) +{ + sfxenum_t *soundsid = *((sfxenum_t **)luaL_checkudata(L, 1, META_SOUNDSID)); + skinsound_t i = luaL_checkinteger(L, 2); + if (i >= NUMSKINSOUNDS) + return luaL_error(L, LUA_QL("skinsound_t") " cannot be %u", i); + lua_pushinteger(L, soundsid[i]); + return 1; +} + +// #soundsid -> NUMSKINSOUNDS +static int soundsid_num(lua_State *L) +{ + lua_pushinteger(L, NUMSKINSOUNDS); + return 1; +} + int LUA_SkinLib(lua_State *L) { luaL_newmetatable(L, META_SKIN); @@ -288,6 +308,14 @@ int LUA_SkinLib(lua_State *L) lua_setfield(L, -2, "__len"); lua_pop(L,1); + luaL_newmetatable(L, META_SOUNDSID); + lua_pushcfunction(L, soundsid_get); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, soundsid_num); + lua_setfield(L, -2, "__len"); + lua_pop(L,1); + lua_newuserdata(L, 0); lua_createtable(L, 0, 2); lua_pushcfunction(L, lib_getSkin); diff --git a/src/m_cheat.c b/src/m_cheat.c index 16bd88ad8..8cea4c6ae 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -16,6 +16,7 @@ #include "g_game.h" #include "s_sound.h" +#include "r_local.h" #include "p_local.h" #include "p_setup.h" #include "d_net.h" @@ -336,6 +337,22 @@ void Command_Hurtme_f(void) P_DamageMobj(players[consoleplayer].mo, NULL, NULL, atoi(COM_Argv(1))); } +// Moves the NiGHTS player to another axis within the current mare +void Command_JumpToAxis_f(void) +{ + REQUIRE_DEVMODE; + REQUIRE_INLEVEL; + REQUIRE_SINGLEPLAYER; + + if (COM_Argc() != 2) + { + CONS_Printf(M_GetText("jumptoaxis : Jump to axis within current mare.\n")); + return; + } + + P_TransferToAxis(&players[consoleplayer], atoi(COM_Argv(1))); +} + void Command_Charability_f(void) { REQUIRE_DEVMODE; @@ -384,6 +401,171 @@ void Command_Charspeed_f(void) CONS_Printf(M_GetText("charspeed : set character speed\n")); } +void Command_RTeleport_f(void) +{ + fixed_t intx, inty, intz; + size_t i; + player_t *p = &players[consoleplayer]; + subsector_t *ss; + + REQUIRE_DEVMODE; + REQUIRE_INLEVEL; + REQUIRE_SINGLEPLAYER; + + if (COM_Argc() < 3 || COM_Argc() > 7) + { + CONS_Printf(M_GetText("rteleport -x -y -z : relative teleport to a location\n")); + return; + } + + if (!p->mo) + return; + + i = COM_CheckParm("-x"); + if (i) + intx = atoi(COM_Argv(i + 1)); + else + intx = 0; + + i = COM_CheckParm("-y"); + if (i) + inty = atoi(COM_Argv(i + 1)); + else + inty = 0; + + ss = R_PointInSubsector(p->mo->x + intx*FRACUNIT, p->mo->y + inty*FRACUNIT); + if (!ss || ss->sector->ceilingheight - ss->sector->floorheight < p->mo->height) + { + CONS_Alert(CONS_NOTICE, M_GetText("Not a valid location.\n")); + return; + } + i = COM_CheckParm("-z"); + if (i) + { + intz = atoi(COM_Argv(i + 1)); + intz <<= FRACBITS; + intz += p->mo->z; + if (intz < ss->sector->floorheight) + intz = ss->sector->floorheight; + if (intz > ss->sector->ceilingheight - p->mo->height) + intz = ss->sector->ceilingheight - p->mo->height; + } + else + intz = p->mo->z; + + CONS_Printf(M_GetText("Teleporting by %d, %d, %d...\n"), intx, inty, FixedInt((intz-p->mo->z))); + + P_MapStart(); + if (!P_TeleportMove(p->mo, p->mo->x+intx*FRACUNIT, p->mo->y+inty*FRACUNIT, intz)) + CONS_Alert(CONS_WARNING, M_GetText("Unable to teleport to that spot!\n")); + else + S_StartSound(p->mo, sfx_mixup); + P_MapEnd(); +} + +void Command_Teleport_f(void) +{ + fixed_t intx, inty, intz; + size_t i; + player_t *p = &players[consoleplayer]; + subsector_t *ss; + + REQUIRE_DEVMODE; + REQUIRE_INLEVEL; + REQUIRE_SINGLEPLAYER; + + if (COM_Argc() < 3 || COM_Argc() > 7) + { + CONS_Printf(M_GetText("teleport -x -y -z : teleport to a location\n")); + return; + } + + if (!p->mo) + return; + + i = COM_CheckParm("-x"); + if (i) + intx = atoi(COM_Argv(i + 1)); + else + { + CONS_Alert(CONS_NOTICE, M_GetText("%s value not specified\n"), "X"); + return; + } + + i = COM_CheckParm("-y"); + if (i) + inty = atoi(COM_Argv(i + 1)); + else + { + CONS_Alert(CONS_NOTICE, M_GetText("%s value not specified\n"), "Y"); + return; + } + + ss = R_PointInSubsector(intx*FRACUNIT, inty*FRACUNIT); + if (!ss || ss->sector->ceilingheight - ss->sector->floorheight < p->mo->height) + { + CONS_Alert(CONS_NOTICE, M_GetText("Not a valid location.\n")); + return; + } + i = COM_CheckParm("-z"); + if (i) + { + intz = atoi(COM_Argv(i + 1)); + intz <<= FRACBITS; + if (intz < ss->sector->floorheight) + intz = ss->sector->floorheight; + if (intz > ss->sector->ceilingheight - p->mo->height) + intz = ss->sector->ceilingheight - p->mo->height; + } + else + intz = ss->sector->floorheight; + + CONS_Printf(M_GetText("Teleporting to %d, %d, %d...\n"), intx, inty, FixedInt(intz)); + + P_MapStart(); + if (!P_TeleportMove(p->mo, intx*FRACUNIT, inty*FRACUNIT, intz)) + CONS_Alert(CONS_WARNING, M_GetText("Unable to teleport to that spot!\n")); + else + S_StartSound(p->mo, sfx_mixup); + P_MapEnd(); +} + +void Command_Skynum_f(void) +{ + REQUIRE_DEVMODE; + REQUIRE_INLEVEL; + REQUIRE_SINGLEPLAYER; + + if (COM_Argc() != 2) + { + CONS_Printf(M_GetText("skynum : change the sky\n")); + CONS_Printf(M_GetText("Current sky is %d\n"), levelskynum); + return; + } + + CONS_Printf(M_GetText("Previewing sky %s...\n"), COM_Argv(1)); + + P_SetupLevelSky(atoi(COM_Argv(1)), false); +} + +void Command_Weather_f(void) +{ + REQUIRE_DEVMODE; + REQUIRE_INLEVEL; + REQUIRE_SINGLEPLAYER; + + if (COM_Argc() != 2) + { + CONS_Printf(M_GetText("weather : change the weather\n")); + CONS_Printf(M_GetText("Current weather is %d\n"), curWeather); + return; + } + + CONS_Printf(M_GetText("Previewing weather %s...\n"), COM_Argv(1)); + + P_SwitchWeather(atoi(COM_Argv(1))); +} + #ifdef _DEBUG // You never thought you needed this, did you? >=D // Yes, this has the specific purpose of completely screwing you up @@ -795,13 +977,6 @@ void OP_NightsObjectplace(player_t *player) if (!OP_HeightOkay(player, false)) return; - angle = (UINT16)((360-player->anotherflyangle) % 360); - if (angle > 90 && angle < 270) - { - angle += 180; - angle %= 360; - } - if (player->mo->target->flags & MF_AMBUSH) angle = (UINT16)player->anotherflyangle; else diff --git a/src/m_cheat.h b/src/m_cheat.h index 98001c5ec..b9c73ee18 100644 --- a/src/m_cheat.h +++ b/src/m_cheat.h @@ -57,8 +57,13 @@ void Command_Devmode_f(void); void Command_Scale_f(void); void Command_Gravflip_f(void); void Command_Hurtme_f(void); +void Command_JumpToAxis_f(void); void Command_Charability_f(void); void Command_Charspeed_f(void); +void Command_Teleport_f(void); +void Command_RTeleport_f(void); +void Command_Skynum_f(void); +void Command_Weather_f(void); #ifdef _DEBUG void Command_CauseCfail_f(void); #endif diff --git a/src/m_menu.c b/src/m_menu.c index 653576f4e..605096465 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -6244,8 +6244,13 @@ static void M_DrawSetupMultiPlayerMenu(void) // draw player sprite if (!setupm_fakecolor) // should never happen but hey, who knows { - if (skins[setupm_fakeskin].flags & SF_HIRES && skins[setupm_fakeskin].highresscale == FRACUNIT>>1) - V_DrawSmallScaledPatch(mx + 98 + (PLBOXW*8/2), my + 16 + (PLBOXH*8) - 12, flags, patch); + if (skins[setupm_fakeskin].flags & SF_HIRES) + { + V_DrawSciencePatch((mx+98+(PLBOXW*8/2))<>1) - V_DrawSmallMappedPatch(mx + 98 + (PLBOXW*8/2), my + 16 + (PLBOXH*8) - 12, flags, patch, colormap); + if (skins[setupm_fakeskin].flags & SF_HIRES) + { + V_DrawFixedPatch((mx+98+(PLBOXW*8/2))<tracer->x - actor->x, actor->tracer->y - actor->y); - exact = R_PointToAngle2(actor->x, actor->z, actor->x + xydist, actor->tracer->z); + exact = R_PointToAngle2(0, 0, xydist, actor->tracer->z - actor->z); actor->movedir = exact; /*if (exact != actor->movedir) { @@ -6730,7 +6730,8 @@ void A_BuzzFly(mobj_t *actor) actor->momz = FixedMul(FixedDiv(actor->target->z - actor->z, dist), realspeed); if (actor->z+actor->momz >= actor->waterbottom && actor->watertop > actor->floorz - && actor->z+actor->momz > actor->watertop - FixedMul(256*FRACUNIT, actor->scale)) + && actor->z+actor->momz > actor->watertop - FixedMul(256*FRACUNIT, actor->scale) + && actor->z+actor->momz <= actor->watertop) { actor->momz = 0; actor->z = actor->watertop; @@ -7299,11 +7300,16 @@ void A_SpawnObjectRelative(mobj_t *actor) // void A_ChangeAngleRelative(mobj_t *actor) { + // Oh god, the old code /sucked/. Changed this and the absolute version to get a random range using amin and amax instead of + // getting a random angle from the _entire_ spectrum and then clipping. While we're at it, do the angle conversion to the result + // rather than the ranges, so <0 and >360 work as possible values. -Red INT32 locvar1 = var1; INT32 locvar2 = var2; - angle_t angle = (P_Random()+1)<<24; - const angle_t amin = FixedAngle(locvar1*FRACUNIT); - const angle_t amax = FixedAngle(locvar2*FRACUNIT); + //angle_t angle = (P_Random()+1)<<24; + const fixed_t amin = locvar1*FRACUNIT; + const fixed_t amax = locvar2*FRACUNIT; + //const angle_t amin = FixedAngle(locvar1*FRACUNIT); + //const angle_t amax = FixedAngle(locvar2*FRACUNIT); #ifdef HAVE_BLUA if (LUA_CallAction("A_ChangeAngleRelative", actor)) return; @@ -7313,13 +7319,13 @@ void A_ChangeAngleRelative(mobj_t *actor) if (amin > amax) I_Error("A_ChangeAngleRelative: var1 is greater then var2"); #endif - +/* if (angle < amin) angle = amin; if (angle > amax) - angle = amax; + angle = amax;*/ - actor->angle += angle; + actor->angle += FixedAngle(P_RandomRange(amin, amax)); } // Function: A_ChangeAngleAbsolute @@ -7333,9 +7339,11 @@ void A_ChangeAngleAbsolute(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2; - angle_t angle = (P_Random()+1)<<24; - const angle_t amin = FixedAngle(locvar1*FRACUNIT); - const angle_t amax = FixedAngle(locvar2*FRACUNIT); + //angle_t angle = (P_Random()+1)<<24; + const fixed_t amin = locvar1*FRACUNIT; + const fixed_t amax = locvar2*FRACUNIT; + //const angle_t amin = FixedAngle(locvar1*FRACUNIT); + //const angle_t amax = FixedAngle(locvar2*FRACUNIT); #ifdef HAVE_BLUA if (LUA_CallAction("A_ChangeAngelAbsolute", actor)) return; @@ -7345,13 +7353,13 @@ void A_ChangeAngleAbsolute(mobj_t *actor) if (amin > amax) I_Error("A_ChangeAngleAbsolute: var1 is greater then var2"); #endif - +/* if (angle < amin) angle = amin; if (angle > amax) - angle = amax; + angle = amax;*/ - actor->angle = angle; + actor->angle = FixedAngle(P_RandomRange(amin, amax)); } // Function: A_PlaySound @@ -9313,9 +9321,15 @@ void A_SpikeRetract(mobj_t *actor) return; if (locvar1 == 0) + { actor->flags &= ~MF_SOLID; + actor->flags |= MF_NOCLIPTHING; + } else + { actor->flags |= MF_SOLID; + actor->flags &= ~MF_NOCLIPTHING; + } if (actor->flags & MF_SOLID) P_CheckPosition(actor, actor->x, actor->y); } diff --git a/src/p_floor.c b/src/p_floor.c index 836df06c2..6d28175eb 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -31,7 +31,7 @@ static inline boolean P_MobjReadyToMove(mobj_t *mo, sector_t *sec, boolean secto { if (sectorisquicksand) return (mo->z > sec->floorheight && mo->z < sec->ceilingheight); - else if (((mo->flags & MF_SPAWNCEILING) == MF_SPAWNCEILING) ^ ((mo->eflags & MFE_VERTICALFLIP) == MFE_VERTICALFLIP)) + else if (!!(mo->flags & MF_SPAWNCEILING) ^ !!(mo->eflags & MFE_VERTICALFLIP)) return ((sectorisffloor) ? (mo->z+mo->height != sec->floorheight) : (mo->z+mo->height != sec->ceilingheight)); else return ((sectorisffloor) ? (mo->z != sec->ceilingheight) : (mo->z != sec->floorheight)); @@ -241,7 +241,7 @@ result_e T_MovePlane(sector_t *sector, fixed_t speed, fixed_t dest, boolean crus // Is the object hang from the ceiling? // In that case, swap the planes used. // verticalflip inverts - if (((mo->flags & MF_SPAWNCEILING) == MF_SPAWNCEILING) ^ ((mo->eflags & MFE_VERTICALFLIP) == MFE_VERTICALFLIP)) + if (!!(mo->flags & MF_SPAWNCEILING) ^ !!(mo->eflags & MFE_VERTICALFLIP)) { if (sectorisffloor && !sectorisquicksand) mo->z = mo->ceilingz - mo->height; @@ -886,9 +886,8 @@ void T_BounceCheese(levelspecthink_t *bouncer) bouncer->speed += gravity; } - if (bouncer->speed < 2*FRACUNIT && bouncer->speed > -2*FRACUNIT - && bouncer->sector->ceilingheight < bouncer->ceilingwasheight + FRACUNIT/4 - && bouncer->sector->ceilingheight > bouncer->ceilingwasheight - FRACUNIT/4) + if (abs(bouncer->speed) < 2*FRACUNIT + && abs(bouncer->sector->ceilingheight-bouncer->ceilingwasheight) < FRACUNIT/4) { bouncer->sector->floorheight = bouncer->floorwasheight; bouncer->sector->ceilingheight = bouncer->ceilingwasheight; @@ -1997,7 +1996,7 @@ void T_NoEnemiesSector(levelspecthink_t *nobaddies) { thing = node->m_thing; - if (((thing->flags & MF_ENEMY) || (thing->flags & MF_BOSS)) && thing->health > 0 + if ((thing->flags & (MF_ENEMY|MF_BOSS)) && thing->health > 0 && thing->z < upperbound && thing->z+thing->height > lowerbound) { exists = true; @@ -2027,12 +2026,12 @@ foundenemy: // // Helper function for T_EachTimeThinker // -static INT32 P_HavePlayersEnteredArea(INT32 *curPlayers, INT32 *oldPlayers, boolean inAndOut) +static INT32 P_HavePlayersEnteredArea(boolean *curPlayers, boolean *oldPlayers, boolean inAndOut) { INT32 i; // Easy check... nothing has changed - if (!memcmp(curPlayers, oldPlayers, sizeof(INT32)*MAXPLAYERS)) + if (!memcmp(curPlayers, oldPlayers, sizeof(boolean)*MAXPLAYERS)) return -1; // Otherwise, we have to check if any new players have entered @@ -2061,15 +2060,15 @@ void T_EachTimeThinker(levelspecthink_t *eachtime) size_t i, j; sector_t *sec = NULL; sector_t *targetsec = NULL; - sector_t *usesec = NULL; + //sector_t *usesec = NULL; INT32 secnum = -1; INT32 affectPlayer = 0; - INT32 oldPlayersInArea[MAXPLAYERS]; - INT32 playersInArea[MAXPLAYERS]; - INT32 oldPlayersOnArea[MAXPLAYERS]; - INT32 playersOnArea[MAXPLAYERS]; - INT32 *oldPlayersArea; - INT32 *playersArea; + boolean oldPlayersInArea[MAXPLAYERS]; + boolean playersInArea[MAXPLAYERS]; + boolean oldPlayersOnArea[MAXPLAYERS]; + boolean playersOnArea[MAXPLAYERS]; + boolean *oldPlayersArea; + boolean *playersArea; boolean FOFsector = false; boolean inAndOut = false; boolean floortouch = false; @@ -2089,14 +2088,23 @@ void T_EachTimeThinker(levelspecthink_t *eachtime) oldPlayersOnArea[i] = eachtime->var2s[i/2] >> 16; } - playersInArea[i] = 0; - playersOnArea[i] = 0; + playersInArea[i] = false; + playersOnArea[i] = false; } while ((secnum = P_FindSectorFromLineTag(eachtime->sourceline, secnum)) >= 0) { sec = §ors[secnum]; + FOFsector = false; + + if (GETSECSPECIAL(sec->special, 2) == 3 || GETSECSPECIAL(sec->special, 2) == 5) + floortouch = true; + else if (GETSECSPECIAL(sec->special, 2) >= 1 && GETSECSPECIAL(sec->special, 2) <= 8) + floortouch = false; + else + continue; + // Check the lines of this sector, to see if it is a FOF control sector. for (i = 0; i < sec->linecount; i++) { @@ -2111,11 +2119,6 @@ void T_EachTimeThinker(levelspecthink_t *eachtime) { targetsec = §ors[targetsecnum]; - if (GETSECSPECIAL(targetsec->special, 2) == 3 || GETSECSPECIAL(targetsec->special, 2) == 5) - floortouch = true; - else - floortouch = false; - for (j = 0; j < MAXPLAYERS; j++) { if (!playeringame[j]) @@ -2146,7 +2149,7 @@ void T_EachTimeThinker(levelspecthink_t *eachtime) else eachtime->var2s[j/2] |= 1 << 16; - playersOnArea[j] = 1; + playersOnArea[j] = true; } else { @@ -2155,7 +2158,7 @@ void T_EachTimeThinker(levelspecthink_t *eachtime) else eachtime->vars[j/2] |= 1 << 16; - playersInArea[j] = 1; + playersInArea[j] = true; } } } @@ -2163,11 +2166,6 @@ void T_EachTimeThinker(levelspecthink_t *eachtime) if (!FOFsector) { - if (GETSECSPECIAL(sec->special, 2) == 3 || GETSECSPECIAL(sec->special, 2) == 5) - floortouch = true; - else - floortouch = false; - for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i]) @@ -2192,7 +2190,7 @@ void T_EachTimeThinker(levelspecthink_t *eachtime) else eachtime->var2s[i/2] |= 1 << 16; - playersOnArea[i] = 1; + playersOnArea[i] = true; } else { @@ -2201,17 +2199,12 @@ void T_EachTimeThinker(levelspecthink_t *eachtime) else eachtime->vars[i/2] |= 1 << 16; - playersInArea[i] = 1; + playersInArea[i] = true; } } } } - if (FOFsector && targetsec) - usesec = targetsec; - else - usesec = sec; - if ((eachtime->sourceline->flags & ML_BOUNCY) == ML_BOUNCY) inAndOut = true; @@ -2231,12 +2224,34 @@ void T_EachTimeThinker(levelspecthink_t *eachtime) if ((affectPlayer = P_HavePlayersEnteredArea(playersArea, oldPlayersArea, inAndOut)) != -1) { + if (GETSECSPECIAL(sec->special, 2) == 2 || GETSECSPECIAL(sec->special, 2) == 3) + { + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + + if (!players[i].mo) + continue; + + if (players[i].mo->health <= 0) + continue; + + if ((netgame || multiplayer) && players[i].spectator) + continue; + + if (!playersArea[i]) + return; + } + } + CONS_Debug(DBG_GAMELOGIC, "Trying to activate each time executor with tag %d\n", eachtime->sourceline->tag); - // Fake-out P_LinedefExecute into thinking you are a continuous. - eachtime->sourceline->special--; - P_LinedefExecute(eachtime->sourceline->tag, players[affectPlayer].mo, usesec); - eachtime->sourceline->special++; + // 03/08/14 -Monster Iestyn + // No more stupid hacks involving changing eachtime->sourceline's tag or special or whatever! + // This should now run ONLY the stuff for eachtime->sourceline itself, instead of all trigger linedefs sharing the same tag. + // Makes much more sense doing it this way, honestly. + P_RunTriggerLinedef(eachtime->sourceline, players[affectPlayer].mo, sec); } } diff --git a/src/p_inter.c b/src/p_inter.c index c55c3cf71..f66bf12f3 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -295,9 +295,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; } - if (((toucher->player->pflags & PF_NIGHTSMODE) && (toucher->player->pflags & PF_DRILLING)) - || (toucher->player->pflags & (PF_JUMPED|PF_SPINNING|PF_GLIDING)) - || toucher->player->powers[pw_invulnerability] || toucher->player->powers[pw_super]) // Do you possess the ability to subdue the object? + if (((player->pflags & PF_NIGHTSMODE) && (player->pflags & PF_DRILLING)) + || (player->pflags & (PF_JUMPED|PF_SPINNING|PF_GLIDING)) + || player->powers[pw_invulnerability] || player->powers[pw_super]) // Do you possess the ability to subdue the object? { if (P_MobjFlip(toucher)*toucher->momz < 0) toucher->momz = -toucher->momz; @@ -307,8 +307,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } else if (((toucher->z < special->z && !(toucher->eflags & MFE_VERTICALFLIP)) || (toucher->z + toucher->height > special->z + special->height && (toucher->eflags & MFE_VERTICALFLIP))) - && toucher->player->charability == CA_FLY - && (toucher->player->powers[pw_tailsfly] + && player->charability == CA_FLY + && (player->powers[pw_tailsfly] || (toucher->state >= &states[S_PLAY_SPC1] && toucher->state <= &states[S_PLAY_SPC4]))) // Tails can shred stuff with his propeller. { toucher->momz = -toucher->momz/2; @@ -325,8 +325,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) //////////////////////////////////////////////////////// /////ENEMIES!!////////////////////////////////////////// //////////////////////////////////////////////////////// - if (special->type == MT_GSNAPPER && !(((toucher->player->pflags & PF_NIGHTSMODE) && (toucher->player->pflags & PF_DRILLING)) - || toucher->player->powers[pw_invulnerability] || toucher->player->powers[pw_super]) + if (special->type == MT_GSNAPPER && !(((player->pflags & PF_NIGHTSMODE) && (player->pflags & PF_DRILLING)) + || player->powers[pw_invulnerability] || player->powers[pw_super]) && toucher->z < special->z + special->height && toucher->z + toucher->height > special->z) { // Can only hit snapper from above @@ -338,9 +338,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) // Cannot hit sharp from above or when red and angry P_DamageMobj(toucher, special, special, 1); } - else if (((toucher->player->pflags & PF_NIGHTSMODE) && (toucher->player->pflags & PF_DRILLING)) - || (toucher->player->pflags & (PF_JUMPED|PF_SPINNING|PF_GLIDING)) - || toucher->player->powers[pw_invulnerability] || toucher->player->powers[pw_super]) // Do you possess the ability to subdue the object? + else if (((player->pflags & PF_NIGHTSMODE) && (player->pflags & PF_DRILLING)) + || (player->pflags & (PF_JUMPED|PF_SPINNING|PF_GLIDING)) + || player->powers[pw_invulnerability] || player->powers[pw_super]) // Do you possess the ability to subdue the object? { if (P_MobjFlip(toucher)*toucher->momz < 0) toucher->momz = -toucher->momz; @@ -349,8 +349,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } else if (((toucher->z < special->z && !(toucher->eflags & MFE_VERTICALFLIP)) || (toucher->z + toucher->height > special->z + special->height && (toucher->eflags & MFE_VERTICALFLIP))) // Flame is bad at logic - JTE - && toucher->player->charability == CA_FLY - && (toucher->player->powers[pw_tailsfly] + && player->charability == CA_FLY + && (player->powers[pw_tailsfly] || (toucher->state >= &states[S_PLAY_SPC1] && toucher->state <= &states[S_PLAY_SPC4]))) // Tails can shred stuff with his propeller. { if (P_MobjFlip(toucher)*toucher->momz < 0) @@ -429,7 +429,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) case MT_GRENADEPICKUP: case MT_EXPLODEPICKUP: case MT_RAILPICKUP: - if (!(P_CanPickupItem(toucher->player, true))) + if (!(P_CanPickupItem(player, true))) return; // Give the power and ringweapon @@ -453,7 +453,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) case MT_GRENADERING: case MT_EXPLOSIONRING: case MT_RAILRING: - if (!(P_CanPickupItem(toucher->player, true))) + if (!(P_CanPickupItem(player, true))) return; if (special->info->mass >= pw_infinityring && special->info->mass <= pw_railring) @@ -541,7 +541,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) // Power stones / Match emeralds case MT_FLINGEMERALD: - if (!(P_CanPickupItem(toucher->player, true)) || player->tossdelay) + if (!(P_CanPickupItem(player, true)) || player->tossdelay) return; player->powers[pw_emeralds] |= special->threshold; @@ -612,10 +612,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) player->gotflag |= flagflag; CONS_Printf(M_GetText("%s picked up the %s flag!\n"), player_names[player-players], flagtext); (*flagmobj) = NULL; - player->pflags &= ~PF_GLIDING; - player->climbing = 0; - if (player->powers[pw_tailsfly]) - player->powers[pw_tailsfly] = 1; + // code for dealing with abilities is handled elsewhere now break; } } @@ -627,55 +624,46 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) case MT_NIGHTSDRONE: if (player->bot) return; - if (G_IsSpecialStage(gamemap) && player->bonustime && !player->exiting) + if (player->exiting) + return; + if (player->bonustime) { - // only allow the player with the emerald in-hand to leave. - if (player->mo->tracer && player->mo->tracer->target - && player->mo->tracer->target->type == MT_GOTEMERALD) + if (G_IsSpecialStage(gamemap)) //After-mare bonus time/emerald reward in special stages. { - P_NightserizePlayer(player, special->health); + // only allow the player with the emerald in-hand to leave. + if (toucher->tracer && toucher->tracer->target + && toucher->tracer->target->type == MT_GOTEMERALD) + { + } + else // Make sure that SOMEONE has the emerald, at least! + { + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && players[i].playerstate == PST_LIVE + && players[i].mo->tracer && players[i].mo->tracer->target + && players[i].mo->tracer->target->type == MT_GOTEMERALD) + return; + // Well no one has an emerald, so exit anyway! + } P_GiveEmerald(false); // Don't play Ideya sound in special stage mode } - else // Make sure that SOMEONE has the emerald, at least! - { - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].playerstate == PST_LIVE - && players[i].mo->tracer && players[i].mo->tracer->target - && players[i].mo->tracer->target->type == MT_GOTEMERALD) - return; - // Well no one has an emerald, so exit anyway! - P_NightserizePlayer(player, special->health); - P_GiveEmerald(false); - } + else + S_StartSound(toucher, special->info->activesound); } - else if (player->bonustime && !player->exiting) //After-mare bonus time/emerald reward in special stages. + else //Initial transformation. Don't allow second chances in special stages! { - if (!(player->pflags & PF_NIGHTSMODE)) - { - if (!(netgame || multiplayer)) - P_SetTarget(&special->tracer, toucher); - P_SetTarget(&toucher->tracer, P_SpawnMobj(toucher->x, toucher->y, toucher->z, MT_NIGHTSCHAR)); - } + if (player->pflags & PF_NIGHTSMODE) + return; - P_NightserizePlayer(player, special->health); - S_StartSound(toucher, special->info->activesound); - } - else if (!G_IsSpecialStage(gamemap) || !player->exiting) //Initial transformation. Don't allow second chances in special stages! - { - if (!(player->pflags & PF_NIGHTSMODE)) - { - if (!(netgame || multiplayer)) - P_SetTarget(&special->tracer, toucher); - S_StartSound(toucher, sfx_supert); - P_SetTarget(&toucher->tracer, P_SpawnMobj(toucher->x, toucher->y, toucher->z, MT_NIGHTSCHAR)); - P_NightserizePlayer(player, special->health); - } + S_StartSound(toucher, sfx_supert); } + if (!(netgame || multiplayer) && !(player->pflags & PF_NIGHTSMODE)) + P_SetTarget(&special->tracer, toucher); + P_NightserizePlayer(player, special->health); // Transform! return; case MT_NIGHTSLOOPHELPER: // One second delay - if (special->fuse < player->mo->fuse - TICRATE) + if (special->fuse < toucher->fuse - TICRATE) { thinker_t *th; mobj_t *mo2; @@ -796,10 +784,13 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; // make sure everything is as it should be, THEN take rings from players in special stages - if ((player->pflags & PF_NIGHTSMODE) && !(toucher->target)) + if (player->pflags & PF_NIGHTSMODE && !toucher->target) return; - if (player->mare != special->threshold) + if (player->mare != special->threshold) // wrong mare + return; + + if (special->reactiontime > 0) // capsule already has a player attacking it, ignore return; if (G_IsSpecialStage(gamemap) && !player->exiting) @@ -807,8 +798,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && (&players[i] != player) && players[i].mo->health > 1) { - player->mo->health += players[i].mo->health-1; - player->health = player->mo->health; + toucher->health += players[i].mo->health-1; + player->health = toucher->health; players[i].mo->health = 1; players[i].health = players[i].mo->health; } @@ -832,7 +823,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (player->bumpertime < TICRATE/4) { - S_StartSound(player->mo, special->info->seesound); + S_StartSound(toucher, special->info->seesound); if (player->pflags & PF_NIGHTSMODE) { player->bumpertime = TICRATE/2; @@ -848,7 +839,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) //player->mo->x = special->x; //player->mo->y = special->y; //P_SetThingPosition(player->mo); - player->mo->z = special->z+(special->height/4); + toucher->z = special->z+(special->height/4); } else // More like a spring { @@ -858,11 +849,11 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) player->bumpertime = TICRATE/2; - P_UnsetThingPosition(player->mo); - player->mo->x = special->x; - player->mo->y = special->y; - P_SetThingPosition(player->mo); - player->mo->z = special->z+(special->height/4); + P_UnsetThingPosition(toucher); + toucher->x = special->x; + toucher->y = special->y; + P_SetThingPosition(toucher); + toucher->z = special->z+(special->height/4); if (special->threshold > 0) fa = (FixedAngle(((special->threshold*30)-1)*FRACUNIT)>>ANGLETOFINESHIFT) & FINEMASK; @@ -872,19 +863,19 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) xspeed = FixedMul(FINECOSINE(fa),speed); yspeed = FixedMul(FINESINE(fa),speed); - P_InstaThrust(player->mo, special->angle, xspeed/10); - player->mo->momz = yspeed/11; + P_InstaThrust(toucher, special->angle, xspeed/10); + toucher->momz = yspeed/11; - player->mo->angle = special->angle; + toucher->angle = special->angle; if (player == &players[consoleplayer]) - localangle = player->mo->angle; + localangle = toucher->angle; else if (player == &players[secondarydisplayplayer]) - localangle2 = player->mo->angle; + localangle2 = toucher->angle; P_ResetPlayer(player); - P_SetPlayerMobjState(player->mo, S_PLAY_FALL1); + P_SetPlayerMobjState(toucher, S_PLAY_FALL1); } } return; @@ -1125,7 +1116,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) case MT_FIREFLOWER: if (player->bot) return; - toucher->player->powers[pw_shield] |= SH_FIREFLOWER; + player->powers[pw_shield] |= SH_FIREFLOWER; toucher->color = SKINCOLOR_WHITE; G_GhostAddColor(GHC_FIREFLOWER); break; @@ -1142,7 +1133,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) { // blatant reuse of a variable that's normally unused in circuit if (!player->tossdelay) - S_StartSound(player->mo, sfx_lose); + S_StartSound(toucher, sfx_lose); player->tossdelay = 3; return; } @@ -1159,8 +1150,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) // Save the player's time and position. player->starposttime = leveltime; - player->starpostx = player->mo->x>>FRACBITS; - player->starposty = player->mo->y>>FRACBITS; + player->starpostx = toucher->x>>FRACBITS; + player->starposty = toucher->y>>FRACBITS; player->starpostz = special->z>>FRACBITS; player->starpostangle = special->angle; player->starpostnum = special->health; @@ -1189,7 +1180,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } } - S_StartSound(player->mo, special->info->painsound); + S_StartSound(toucher, special->info->painsound); if (!(netgame && circuitmap && player != &players[consoleplayer])) P_SetMobjState(special, special->info->painstate); @@ -1242,7 +1233,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (player->pflags & PF_ITEMHANG) { - P_SetTarget(&player->mo->tracer, NULL); + P_SetTarget(&toucher->tracer, NULL); player->pflags &= ~PF_ITEMHANG; } @@ -1295,8 +1286,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) S_StartSound(toucher, special->info->painsound); return; } - else if (((toucher->player->pflags & PF_NIGHTSMODE) && (toucher->player->pflags & PF_DRILLING)) || (toucher->player->pflags & (PF_JUMPED|PF_SPINNING|PF_GLIDING)) - || toucher->player->powers[pw_invulnerability] || toucher->player->powers[pw_super]) // Do you possess the ability to subdue the object? + else if (((player->pflags & PF_NIGHTSMODE) && (player->pflags & PF_DRILLING)) || (player->pflags & (PF_JUMPED|PF_SPINNING|PF_GLIDING)) + || player->powers[pw_invulnerability] || player->powers[pw_super]) // Do you possess the ability to subdue the object? { // Shatter the shield! toucher->momx = -toucher->momx/2; @@ -1344,7 +1335,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) { player->pflags |= PF_MACESPIN; S_StartSound(toucher, sfx_spin); - P_SetPlayerMobjState(player->mo, S_PLAY_ATK1); + P_SetPlayerMobjState(toucher, S_PLAY_ATK1); } else player->pflags |= PF_ITEMHANG; @@ -1370,7 +1361,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (player->powers[pw_shield] || player->bot) //If One-Hit Shield { P_RemoveShield(player); - S_StartSound(player->mo, sfx_shldls); // Ba-Dum! Shield loss. + S_StartSound(toucher, sfx_shldls); // Ba-Dum! Shield loss. } else { @@ -1409,8 +1400,14 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; if (mariomode) return; - else if (special->z < player->mo->z + player->mo->height / 3 - || special->z > player->mo->z + (player->mo->height*2/3)) + else if (toucher->eflags & MFE_VERTICALFLIP) + { + if (special->z+special->height < toucher->z + toucher->height / 3 + || special->z+special->height > toucher->z + (toucher->height*2/3)) + return; // Only go in the mouth + } + else if (special->z < toucher->z + toucher->height / 3 + || special->z > toucher->z + (toucher->height*2/3)) return; // Only go in the mouth // Eaten by player! @@ -1422,11 +1419,11 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (!player->climbing) { - P_SetPlayerMobjState(player->mo, S_PLAY_GASP); + P_SetPlayerMobjState(toucher, S_PLAY_GASP); P_ResetPlayer(player); } - player->mo->momx = player->mo->momy = player->mo->momz = 0; + toucher->momx = toucher->momy = toucher->momz = 0; break; case MT_WATERDROP: @@ -1480,6 +1477,11 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour if (!netgame) return; // Presumably it's obvious what's happening in splitscreen. +#ifdef HAVE_BLUA + if (LUAh_DeathMsg(player, inflictor, source)) + return; +#endif + deadtarget = (player->health <= 0); // Target's name @@ -2188,6 +2190,19 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source) target->fuse = TICRATE*2; break; + case MT_PLAYER: + target->fuse = TICRATE*3; // timer before mobj disappears from view (even if not an actual player) + target->momx = target->momy = target->momz = 0; + if (!(source && source->type == MT_NULL && source->threshold == 42)) // Don't jump up when drowning + P_SetObjectMomZ(target, 14*FRACUNIT, false); + + if (source && source->type == MT_NULL && source->threshold == 42) // drowned + S_StartSound(target, sfx_drown); + else if (source && (source->type == MT_SPIKE || (source->type == MT_NULL && source->threshold == 43))) // Spikes + S_StartSound(target, sfx_spkdth); + else + P_PlayDeathSound(target); + break; default: break; } @@ -2220,6 +2235,29 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source) mo->flags2 |= MF2_OBJECTFLIP; } + if (target->type == MT_EGGMOBILE3) + { + thinker_t *th; + UINT32 i = 0; // to check how many clones we've removed + + // scan the thinkers to make sure all the old pinch dummies are gone on death + // this can happen if the boss was hurt earlier than expected + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + mo = (mobj_t *)th; + if (mo->type == (mobjtype_t)target->info->mass && mo->tracer == target) + { + P_RemoveMobj(mo); + i++; + } + if (i == 2) // we've already removed 2 of these, let's stop now + break; + } + } + if (target->type == MT_SPIKE && inflictor && target->info->deathstate != S_NULL) { const fixed_t x=target->x,y=target->y,z=target->z; @@ -2520,27 +2558,14 @@ static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage) // Get rid of shield player->powers[pw_shield] = SH_NONE; player->mo->color = player->skincolor; - player->mo->momx = player->mo->momy = player->mo->momz = 0; // Get rid of emeralds player->powers[pw_emeralds] = 0; - if (player->powers[pw_underwater] != 1) // Don't jump up when drowning - P_SetObjectMomZ(player->mo, 14*FRACUNIT, false); - else - P_SetObjectMomZ(player->mo, 0, false); - P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2); P_ResetPlayer(player); - if (source && source->type == MT_NULL && source->threshold == 42) // drowned - S_StartSound(player->mo, sfx_drown); - else if (source && (source->type == MT_SPIKE || (source->type == MT_NULL && source->threshold == 43))) // Spikes - S_StartSound(player->mo, sfx_spkdth); - else - P_PlayDeathSound(player->mo); - P_SetPlayerMobjState(player->mo, player->mo->info->deathstate); if (gametype == GT_CTF && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))) { diff --git a/src/p_local.h b/src/p_local.h index 2c8d9165d..f5c765fe6 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -128,8 +128,13 @@ boolean P_PlayerInPain(player_t *player); void P_DoPlayerPain(player_t *player, mobj_t *source, mobj_t *inflictor); void P_ResetPlayer(player_t *player); boolean P_IsLocalPlayer(player_t *player); + +boolean P_IsObjectInGoop(mobj_t *mo); boolean P_IsObjectOnGround(mobj_t *mo); boolean P_IsObjectOnGroundIn(mobj_t *mo, sector_t *sec); +boolean P_InSpaceSector(mobj_t *mo); +boolean P_InQuicksand(mobj_t *mo); + void P_SetObjectMomZ(mobj_t *mo, fixed_t value, boolean relative); void P_RestoreMusic(player_t *player); void P_SpawnShieldOrb(player_t *player); @@ -141,8 +146,10 @@ void P_GiveEmerald(boolean spawnObj); void P_ResetScore(player_t *player); boolean P_MenuActivePause(void); +void P_DoJumpShield(player_t *player); void P_BlackOw(player_t *player); void P_ElementalFireTrail(player_t *player); + void P_DoPityCheck(player_t *player); void P_PlayerThink(player_t *player); void P_PlayerAfterThink(player_t *player); diff --git a/src/p_map.c b/src/p_map.c index 64f43477f..fa8b9ed7d 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -45,7 +45,7 @@ static fixed_t preciptmbbox[4]; boolean floatok; fixed_t tmfloorz, tmceilingz; -static fixed_t tmdropoffz; +static fixed_t tmdropoffz, tmdrpoffceilz; // drop-off floor/ceiling heights mobj_t *tmfloorthing; // the thing corresponding to tmfloorz or NULL if tmfloorz is from a sector static mobj_t *tmhitthing; // the solid thing you bumped into (for collisions) @@ -260,10 +260,9 @@ static boolean PIT_CheckThing(mobj_t *thing) // Metal Sonic destroys tiny baby objects. if (tmthing->type == MT_METALSONIC_RACE - && (thing->flags & MF_MISSILE || thing->flags & MF_ENEMY - || thing->flags & MF_BOSS || thing->type == MT_SPIKE)) + && (thing->flags & (MF_MISSILE|MF_ENEMY|MF_BOSS) || thing->type == MT_SPIKE)) { - if ((thing->flags & MF_ENEMY || thing->flags & MF_BOSS) && (thing->health <= 0 || !(thing->flags & MF_SHOOTABLE))) + if ((thing->flags & (MF_ENEMY|MF_BOSS)) && (thing->health <= 0 || !(thing->flags & MF_SHOOTABLE))) return true; blockdist = thing->radius + tmthing->radius; if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist) @@ -538,7 +537,7 @@ static boolean PIT_CheckThing(mobj_t *thing) return false; } - if ((thing->flags & MF_PUSHABLE) && (tmthing->player || tmthing->flags & MF_PUSHABLE) + if (thing->flags & MF_PUSHABLE && (tmthing->player || tmthing->flags & MF_PUSHABLE) && tmthing->z + tmthing->height > thing->z && tmthing->z < thing->z + thing->height && !(netgame && tmthing->player && tmthing->player->spectator)) // Push thing! { @@ -636,19 +635,19 @@ static boolean PIT_CheckThing(mobj_t *thing) // Sprite Spikes! // Do not return because solidity code comes below. - if (tmthing->type == MT_SPIKE && thing->player) // moving spike rams into player?! + if (tmthing->type == MT_SPIKE && tmthing->flags & MF_SOLID && thing->player) // moving spike rams into player?! { if (tmthing->eflags & MFE_VERTICALFLIP) { if (thing->z + thing->height <= tmthing->z + FixedMul(FRACUNIT, tmthing->scale) - && thing->z + thing->height >= tmthing->z + FixedMul(FRACUNIT, tmthing->scale) + tmthing->momz) + && thing->z + thing->height + thing->momz >= tmthing->z + FixedMul(FRACUNIT, tmthing->scale) + tmthing->momz) P_DamageMobj(thing, tmthing, tmthing, 1); } else if (thing->z >= tmthing->z + tmthing->height - FixedMul(FRACUNIT, tmthing->scale) && thing->z + thing->momz <= tmthing->z + tmthing->height - FixedMul(FRACUNIT, tmthing->scale) + tmthing->momz) P_DamageMobj(thing, tmthing, tmthing, 1); } - else if (thing->type == MT_SPIKE && tmthing->player) // unfortunate player falls into spike?! + else if (thing->type == MT_SPIKE && thing->flags & MF_SOLID && tmthing->player) // unfortunate player falls into spike?! { if (thing->eflags & MFE_VERTICALFLIP) { @@ -815,6 +814,10 @@ static boolean PIT_CheckThing(mobj_t *thing) if (thing->player->pflags & PF_NIGHTSMODE) return true; + if (thing->tracer && thing->tracer->type == MT_TUBEWAYPOINT + && !(thing->player->pflags & PF_ROPEHANG)) + return true; // don't steal players from zoomtubes! + if ((thing->eflags & MFE_VERTICALFLIP) != (tmthing->eflags & MFE_VERTICALFLIP)) return true; // Both should be in same gravity @@ -887,7 +890,7 @@ static boolean PIT_CheckThing(mobj_t *thing) && P_IsObjectOnGround(thing) && (tmthing->flags & MF_SOLID)) { - if ((tmthing->flags & MF_MONITOR) || (tmthing->flags & MF_PUSHABLE)) + if (tmthing->flags & (MF_MONITOR|MF_PUSHABLE)) { if (thing != tmthing->target) P_DamageMobj(thing, tmthing, tmthing->target, 10000); @@ -940,7 +943,7 @@ static boolean PIT_CheckThing(mobj_t *thing) && P_IsObjectOnGround(thing) && (tmthing->flags & MF_SOLID)) { - if ((tmthing->flags & MF_MONITOR) || (tmthing->flags & MF_PUSHABLE)) + if (tmthing->flags & (MF_MONITOR|MF_PUSHABLE)) { if (thing != tmthing->target) P_DamageMobj(thing, tmthing, tmthing->target, 10000); @@ -1071,39 +1074,29 @@ static boolean PIT_CheckThing(mobj_t *thing) else if (thing->flags & MF_MONITOR && tmthing->player->pflags & (PF_JUMPED|PF_SPINNING|PF_GLIDING)) { - boolean flip = (thing->eflags & MFE_VERTICALFLIP) != 0; // Save this flag in case monitor gets removed. + SINT8 flipval = P_MobjFlip(thing); // Save this value in case monitor gets removed. fixed_t *momz = &tmthing->momz; // tmthing gets changed by P_DamageMobj, so we need a new pointer?! X_x;; P_DamageMobj(thing, tmthing, tmthing, 1); // break the monitor // Going down? Then bounce back up. if ((P_MobjWasRemoved(thing) // Monitor was removed || !thing->health) // or otherwise popped - && ((!flip && *momz < 0) // monitor is on the floor and you're going down - || (flip && *momz > 0))) // or on the ceiling and you're going up + && (flipval*(*momz) < 0)) // monitor is on the floor and you're going down, or on the ceiling and you're going up *momz = -*momz; // Therefore, you should be thrust in the opposite direction, vertically. return false; } - else if (thing->flags & MF_BOSS - && ((tmthing->player->pflags & PF_JUMPED) || (tmthing->player->pflags & PF_SPINNING) - || tmthing->player->powers[pw_invulnerability] - || tmthing->player->powers[pw_super])) - { - // Going down? Then bounce back up. - if (abs(tmthing->momz) > 0) - tmthing->momz = -tmthing->momz; - - // Also, bounce back. - tmthing->momx = -tmthing->momx; - tmthing->momy = -tmthing->momy; - P_DamageMobj(thing, tmthing, tmthing, 1); // fight the boss! - return false; - } } } + + // Monitors are not treated as solid to players who are jumping, spinning or gliding, + // unless it's a CTF team monitor and you're on the wrong team + if (thing->flags & MF_MONITOR && tmthing->player && tmthing->player->pflags & (PF_JUMPED|PF_SPINNING|PF_GLIDING) + && !((thing->type == MT_REDRINGBOX && tmthing->player->ctfteam != 1) || (thing->type == MT_BLUERINGBOX && tmthing->player->ctfteam != 2))) + ; // z checking at last // Treat noclip things as non-solid! - if ((thing->flags & MF_SOLID) && (tmthing->flags & MF_SOLID) && - !(thing->flags & MF_NOCLIP) && !(tmthing->flags & MF_NOCLIP)) + else if ((thing->flags & (MF_SOLID|MF_NOCLIP)) == MF_SOLID + && (tmthing->flags & (MF_SOLID|MF_NOCLIP)) == MF_SOLID) { if (tmthing->eflags & MFE_VERTICALFLIP) { @@ -1128,7 +1121,9 @@ static boolean PIT_CheckThing(mobj_t *thing) && tmthing->z + tmthing->height < tmthing->ceilingz) return false; // block while in air - if (topz < tmceilingz && !(thing->flags & MF_SPRING)) + if (thing->flags & MF_SPRING) + ; + else if (topz < tmceilingz && tmthing->z+tmthing->height <= thing->z+thing->height) { tmceilingz = topz; tmfloorthing = thing; // thing we may stand on @@ -1156,7 +1151,9 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->player && tmthing->z < topz && tmthing->z > tmthing->floorz) return false; // block while in air - if (topz > tmfloorz && !(thing->flags & MF_SPRING)) + if (thing->flags & MF_SPRING) + ; + else if (topz > tmfloorz && tmthing->z >= thing->z) { tmfloorz = topz; tmfloorthing = thing; // thing we may stand on @@ -1219,6 +1216,9 @@ static boolean PIT_CheckCameraLine(line_t *ld) tmfloorz = openbottom; } + if (highceiling > tmdrpoffceilz) + tmdrpoffceilz = highceiling; + if (lowfloor < tmdropoffz) tmdropoffz = lowfloor; @@ -1266,7 +1266,7 @@ static boolean PIT_CheckLine(line_t *ld) { if (ld->flags & ML_IMPASSIBLE) // block objects from moving through this linedef. return false; - if (((tmthing->flags & MF_ENEMY) || (tmthing->flags & MF_BOSS)) && ld->flags & ML_BLOCKMONSTERS) + if ((tmthing->flags & (MF_ENEMY|MF_BOSS)) && ld->flags & ML_BLOCKMONSTERS) return false; // block monsters only } @@ -1285,6 +1285,9 @@ static boolean PIT_CheckLine(line_t *ld) tmfloorz = openbottom; } + if (highceiling > tmdrpoffceilz) + tmdrpoffceilz = highceiling; + if (lowfloor < tmdropoffz) tmdropoffz = lowfloor; @@ -1314,6 +1317,7 @@ static boolean PIT_CheckLine(line_t *ld) // tmfloorz // tmceilingz // tmdropoffz +// tmdrpoffceilz // the lowest point contacted // (monsters won't move to a dropoff) // speciallines[] @@ -1356,7 +1360,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) // Any contacted lines the step closer together // will adjust them. tmfloorz = tmdropoffz = newsubsec->sector->floorheight; - tmceilingz = newsubsec->sector->ceilingheight; + tmceilingz = tmdrpoffceilz = newsubsec->sector->ceilingheight; // Check list of fake floors and see if tmfloorz/tmceilingz need to be altered. if (newsubsec->sector->ffloors) @@ -1427,16 +1431,15 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) + ((*rover->topheight - *rover->bottomheight)/2)); if (*rover->topheight > tmfloorz && abs(delta1) < abs(delta2) - && (!(rover->flags & FF_REVERSEPLATFORM))) + && !(rover->flags & FF_REVERSEPLATFORM)) { tmfloorz = tmdropoffz = *rover->topheight; } if (*rover->bottomheight < tmceilingz && abs(delta1) >= abs(delta2) - && (/*thing->z + thing->height <= *rover->bottomheight - || */!(rover->flags & FF_PLATFORM)) + && !(rover->flags & FF_PLATFORM) && !(thing->type == MT_SKIM && (rover->flags & FF_SWIMMABLE))) { - tmceilingz = *rover->bottomheight; + tmceilingz = tmdrpoffceilz = *rover->bottomheight; } } } @@ -1506,7 +1509,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) tmfloorz = tmdropoffz = polytop; if (polybottom < tmceilingz && abs(delta1) >= abs(delta2)) - tmceilingz = polybottom; + tmceilingz = tmdrpoffceilz = polybottom; } plink = (polymaplink_t *)(plink->link.next); } @@ -1609,7 +1612,7 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam) if (GETSECSPECIAL(newsubsec->sector->special, 4) == 12) { // Camera noclip on entire sector. tmfloorz = tmdropoffz = thiscam->z; - tmceilingz = thiscam->z + thiscam->height; + tmceilingz = tmdrpoffceilz = thiscam->z + thiscam->height; return true; } @@ -1618,14 +1621,21 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam) // Any contacted lines the step closer together // will adjust them. tmfloorz = tmdropoffz = newsubsec->sector->floorheight; - tmceilingz = newsubsec->sector->ceilingheight; + tmceilingz = tmdrpoffceilz = newsubsec->sector->ceilingheight; // Cameras use the heightsec's heights rather then the actual sector heights. // If you can see through it, why not move the camera through it too? if (newsubsec->sector->heightsec >= 0) { tmfloorz = tmdropoffz = sectors[newsubsec->sector->heightsec].floorheight; - tmceilingz = sectors[newsubsec->sector->heightsec].ceilingheight; + tmceilingz = tmdrpoffceilz = sectors[newsubsec->sector->heightsec].ceilingheight; + } + + // Use preset camera clipping heights if set with Sector Special Parameters whose control sector has Camera Intangible special -Red + if (newsubsec->sector->camsec >= 0) + { + tmfloorz = tmdropoffz = sectors[newsubsec->sector->camsec].floorheight; + tmceilingz = tmdrpoffceilz = sectors[newsubsec->sector->camsec].ceilingheight; } // Check list of fake floors and see if tmfloorz/tmceilingz need to be altered. @@ -1650,7 +1660,7 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam) } if (*rover->bottomheight < tmceilingz && abs(delta1) >= abs(delta2)) { - tmceilingz = *rover->bottomheight; + tmceilingz = tmdrpoffceilz = *rover->bottomheight; } } } @@ -1725,7 +1735,7 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam) tmfloorz = tmdropoffz = polytop; if (polybottom < tmceilingz && abs(delta1) >= abs(delta2)) - tmceilingz = polybottom; + tmceilingz = tmdrpoffceilz = polybottom; } plink = (polymaplink_t *)(plink->link.next); } @@ -1930,11 +1940,13 @@ boolean PIT_PushableMoved(mobj_t *thing) P_SetTarget(&tmthing, oldthing); ceilingline = oldceilline; blockingline = oldblockline; + thing->momz = stand->momz; } else { thing->momx = stand->momx; thing->momy = stand->momy; + thing->momz = stand->momz; } return true; } @@ -1948,6 +1960,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) fixed_t tryx = thing->x; fixed_t tryy = thing->y; fixed_t radius = thing->radius; + fixed_t thingtop = thing->z + thing->height; floatok = false; if (radius < MAXRADIUS/2) @@ -1986,6 +1999,11 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) if (thing->player) { + // If using type Section1:13, double the maxstep. + if (P_PlayerTouchingSectorSpecial(thing->player, 1, 13) + || GETSECSPECIAL(R_PointInSubsector(x, y)->sector->special, 1) == 13) + maxstep <<= 1; + // Don't 'step up' while springing, // Only step up "if needed". if (thing->state == &states[S_PLAY_SPRING] @@ -2014,27 +2032,22 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) return false; // mobj must raise itself to fit } } - else if (tmceilingz - thing->z < thing->height) + else if (tmceilingz < thingtop) { CheckMissileImpact(thing); return false; // mobj must lower itself to fit } - // If using type Section1:13, double the maxstep. - if (thing->player && (P_PlayerTouchingSectorSpecial(thing->player, 1, 13) - || GETSECSPECIAL(R_PointInSubsector(x, y)->sector->special, 1) == 13)) - maxstep <<= 1; - // Ramp test - if (thing->player && !P_PlayerTouchingSectorSpecial(thing->player, 1, 14) - && GETSECSPECIAL(R_PointInSubsector(x, y)->sector->special, 1) != 14) + if (thing->player && maxstep > 0 + && !(P_PlayerTouchingSectorSpecial(thing->player, 1, 14) || GETSECSPECIAL(R_PointInSubsector(x, y)->sector->special, 1) == 14)) { // If the floor difference is MAXSTEPMOVE or less, and the sector isn't Section1:14, ALWAYS // step down! Formerly required a Section1:13 sector for the full MAXSTEPMOVE, but no more. if (thing->eflags & MFE_VERTICALFLIP) { - if (thing->z+thing->height == thing->ceilingz && tmceilingz > thing->z+thing->height && tmceilingz - thing->z+thing->height <= maxstep) + if (thingtop == thing->ceilingz && tmceilingz > thingtop && tmceilingz - thingtop <= maxstep) { thing->z = tmceilingz - thing->height; thing->eflags |= MFE_JUSTSTEPPEDDOWN; @@ -2049,9 +2062,11 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) if (thing->eflags & MFE_VERTICALFLIP) { - if (thing->z + thing->height > tmceilingz + maxstep) + if (thingtop - tmceilingz > maxstep) { CheckMissileImpact(thing); + if (tmfloorthing) + tmhitthing = tmfloorthing; return false; // too big a step up } } @@ -2065,14 +2080,20 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) if (tmfloorz > thing->z) { - if ((thing->flags & MF_MISSILE)) + if (thing->flags & MF_MISSILE) CheckMissileImpact(thing); } - if (!allowdropoff) - if (!(thing->flags & MF_FLOAT) && thing->type != MT_SKIM && !tmfloorthing - && tmfloorz - tmdropoffz > maxstep) + if (!allowdropoff && !(thing->flags & MF_FLOAT) && thing->type != MT_SKIM && !tmfloorthing) + { + if (thing->eflags & MFE_VERTICALFLIP) + { + if (tmdrpoffceilz - tmceilingz > maxstep) + return false; + } + else if (tmfloorz - tmdropoffz > maxstep) return false; // don't stand over a dropoff + } } } while (tryx != x || tryy != y); @@ -2562,7 +2583,7 @@ static boolean PTR_SlideTraverse(intercept_t *in) if (li->flags & ML_IMPASSIBLE) goto isblocking; - if (((slidemo->flags & MF_ENEMY) || (slidemo->flags & MF_BOSS)) && li->flags & ML_BLOCKMONSTERS) + if ((slidemo->flags & (MF_ENEMY|MF_BOSS)) && li->flags & ML_BLOCKMONSTERS) goto isblocking; } @@ -2804,7 +2825,7 @@ void P_SlideMove(mobj_t *mo) INT16 hitcount = 0; boolean success = false; - if (tmhitthing) + if (tmhitthing && mo->z + mo->height > tmhitthing->z && mo->z < tmhitthing->z + tmhitthing->height) { // Don't mess with your momentum if it's a pushable object. Pushables do their own crazy things already. if (tmhitthing->flags & MF_PUSHABLE) @@ -3205,24 +3226,34 @@ static boolean nofit; // static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush) { + mobj_t *killer = NULL; + if (P_ThingHeightClip(thing)) { - // keep checking + //thing fits, check next thing return true; } if (!(thing->flags & (MF_SHOOTABLE|MF_PUSHABLE)) || thing->flags & MF_NOCLIPHEIGHT) { - // assume it is bloody gibs or something + //doesn't interact with the crusher, just ignore it return true; } - // Crush the thing if necessary, and if it's a crumbling FOF that did it, - // reward the player who made it crumble! + // Thing doesn't fit. If thing is vulnerable, that means it's being crushed. If thing is pushable, it might + // just be blocked by another object - check if it's really a ceiling! if (thing->z + thing->height > thing->ceilingz && thing->z <= thing->ceilingz) { - if (realcrush && thing->subsector->sector->ffloors) + if (thing->flags & MF_PUSHABLE && thing->z + thing->height > thing->subsector->sector->ceilingheight) + { + //Thing is a pushable and blocks the moving ceiling + nofit = true; + return false; + } + + //Check FOFs in the sector + if (thing->subsector->sector->ffloors && (realcrush || thing->flags & MF_PUSHABLE)) { ffloor_t *rover; fixed_t delta1, delta2; @@ -3238,50 +3269,53 @@ static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush) delta2 = thingtop - (*rover->bottomheight + *rover->topheight)/2; if (*rover->bottomheight <= thing->ceilingz && abs(delta1) >= abs(delta2)) { - thinker_t *think; - elevator_t *crumbler; - - for (think = thinkercap.next; think != &thinkercap; think = think->next) + if (thing->flags & MF_PUSHABLE) { - if (think->function.acp1 != (actionf_p1)T_StartCrumble) - continue; + //FOF is blocked by pushable + nofit = true; + return false; + } + else + { + //If the thing was crushed by a crumbling FOF, reward the player who made it crumble! + thinker_t *think; + elevator_t *crumbler; - crumbler = (elevator_t *)think; - - if (crumbler->player && crumbler->player->mo - && crumbler->player->mo != thing - && crumbler->actionsector == thing->subsector->sector - && crumbler->sector == rover->master->frontsector - && (crumbler->type == elevateBounce - || crumbler->type == elevateContinuous)) + for (think = thinkercap.next; think != &thinkercap; think = think->next) { - if (netgame && thing->player && thing->player->spectator) - P_DamageMobj(thing, NULL, NULL, 42000); // Respawn crushed spectators - else - P_DamageMobj(thing, crumbler->player->mo, crumbler->player->mo, 10000); - return true; + if (think->function.acp1 != (actionf_p1)T_StartCrumble) + continue; + + crumbler = (elevator_t *)think; + + if (crumbler->player && crumbler->player->mo + && crumbler->player->mo != thing + && crumbler->actionsector == thing->subsector->sector + && crumbler->sector == rover->master->frontsector + && (crumbler->type == elevateBounce + || crumbler->type == elevateContinuous)) + { + killer = crumbler->player->mo; + } } } } } } - if (thing->flags & MF_PUSHABLE) - { - nofit = true; - return false; - } - if (realcrush) { - // Instant-death, but no one to blame + // Crush the object if (netgame && thing->player && thing->player->spectator) P_DamageMobj(thing, NULL, NULL, 42000); // Respawn crushed spectators else { - // So give a generic crush death message - mobj_t *killer = P_SpawnMobj(thing->x, thing->y, thing->z, MT_NULL); - killer->threshold = 44; // Special flag for crushing + if (!killer) + { + //Nobody is responsible for crushing the object, so give a generic crush message + killer = P_SpawnMobj(thing->x, thing->y, thing->z, MT_NULL); + killer->threshold = 44; // Special flag for crushing + } P_DamageMobj(thing, killer, killer, 10000); } } diff --git a/src/p_maputl.c b/src/p_maputl.c index a01b07371..d46080abb 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -91,6 +91,71 @@ void P_ClosestPointOnLine(fixed_t x, fixed_t y, line_t *line, vertex_t *result) return; } +// +// P_ClosestPointOnLine3D +// Finds the closest point on a given line to the supplied point IN 3D!!! +// +void P_ClosestPointOnLine3D(fixed_t x, fixed_t y, fixed_t z, line_t *line, vertex_t *result) +{ + fixed_t startx = line->v1->x; + fixed_t starty = line->v1->y; + fixed_t startz = line->v1->z; + fixed_t dx = line->dx; + fixed_t dy = line->dy; + fixed_t dz = line->v2->z - line->v1->z; + + // Determine t (the length of the vector from �Line[0]� to �p�) + fixed_t cx, cy, cz; + fixed_t vx, vy, vz; + fixed_t magnitude; + fixed_t t; + + //Sub (p, &Line[0], &c); + cx = x - startx; + cy = y - starty; + cz = z - startz; + + //Sub (&Line[1], &Line[0], &V); + vx = dx; + vy = dy; + vz = dz; + + //Normalize (&V, &V); + magnitude = R_PointToDist2(0, line->v2->z, R_PointToDist2(line->v2->x, line->v2->y, startx, starty), startz); + vx = FixedDiv(vx, magnitude); + vy = FixedDiv(vy, magnitude); + vz = FixedDiv(vz, magnitude); + + t = (FixedMul(vx, cx) + FixedMul(vy, cy) + FixedMul(vz, cz)); + + // Set closest point to the end if it extends past -Red + if (t <= 0) + { + result->x = line->v1->x; + result->y = line->v1->y; + result->z = line->v1->z; + return; + } + else if (t >= magnitude) + { + result->x = line->v2->x; + result->y = line->v2->y; + result->z = line->v2->z; + return; + } + + // Return the point between �Line[0]� and �Line[1]� + vx = FixedMul(vx, t); + vy = FixedMul(vy, t); + vz = FixedMul(vz, t); + + //Add (&Line[0], &V, out); + result->x = startx + vx; + result->y = starty + vy; + result->z = startz + vz; + return; +} + // // P_PointOnLineSide // Returns 0 or 1 @@ -255,7 +320,7 @@ fixed_t P_InterceptVector(divline_t *v2, divline_t *v1) // Sets opentop and openbottom to the window through a two sided line. // OPTIMIZE: keep this precalculated // -fixed_t opentop, openbottom, openrange, lowfloor; +fixed_t opentop, openbottom, openrange, lowfloor, highceiling; // P_CameraLineOpening // P_LineOpening, but for camera @@ -278,7 +343,12 @@ void P_CameraLineOpening(line_t *linedef) // Cameras use the heightsec's heights rather then the actual sector heights. // If you can see through it, why not move the camera through it too? - if (front->heightsec >= 0) + if (front->camsec >= 0) + { + frontfloor = sectors[front->camsec].floorheight; + frontceiling = sectors[front->camsec].ceilingheight; + } + else if (front->heightsec >= 0) { frontfloor = sectors[front->heightsec].floorheight; frontceiling = sectors[front->heightsec].ceilingheight; @@ -288,7 +358,12 @@ void P_CameraLineOpening(line_t *linedef) frontfloor = front->floorheight; frontceiling = front->ceilingheight; } - if (back->heightsec >= 0) + if (back->camsec >= 0) + { + backfloor = sectors[back->camsec].floorheight; + backceiling = sectors[back->camsec].ceilingheight; + } + else if (back->heightsec >= 0) { backfloor = sectors[back->heightsec].floorheight; backceiling = sectors[back->heightsec].ceilingheight; @@ -303,9 +378,15 @@ void P_CameraLineOpening(line_t *linedef) fixed_t thingtop = mapcampointer->z + mapcampointer->height; if (frontceiling < backceiling) + { opentop = frontceiling; + highceiling = backceiling; + } else + { opentop = backceiling; + highceiling = frontceiling; + } if (frontfloor > backfloor) { @@ -322,13 +403,12 @@ void P_CameraLineOpening(line_t *linedef) if (front->ffloors || back->ffloors) { ffloor_t *rover; + fixed_t highestceiling = highceiling; fixed_t lowestceiling = opentop; fixed_t highestfloor = openbottom; fixed_t lowestfloor = lowfloor; fixed_t delta1, delta2; - thingtop = mapcampointer->z + mapcampointer->height; - // Check for frontsector's fake floors if (front->ffloors) for (rover = front->ffloors; rover; rover = rover->next) @@ -340,6 +420,8 @@ void P_CameraLineOpening(line_t *linedef) delta2 = abs(thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2))); if (*rover->bottomheight < lowestceiling && delta1 >= delta2) lowestceiling = *rover->bottomheight; + else if (*rover->bottomheight < highestceiling && delta1 >= delta2) + highestceiling = *rover->bottomheight; if (*rover->topheight > highestfloor && delta1 < delta2) highestfloor = *rover->topheight; @@ -358,6 +440,8 @@ void P_CameraLineOpening(line_t *linedef) delta2 = abs(thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2))); if (*rover->bottomheight < lowestceiling && delta1 >= delta2) lowestceiling = *rover->bottomheight; + else if (*rover->bottomheight < highestceiling && delta1 >= delta2) + highestceiling = *rover->bottomheight; if (*rover->topheight > highestfloor && delta1 < delta2) highestfloor = *rover->topheight; @@ -365,6 +449,9 @@ void P_CameraLineOpening(line_t *linedef) lowestfloor = *rover->topheight; } + if (highestceiling < highceiling) + highceiling = highestceiling; + if (highestfloor > openbottom) openbottom = highestfloor; @@ -407,131 +494,16 @@ void P_LineOpening(line_t *linedef) I_Assert(front != NULL); I_Assert(back != NULL); - if (tmthing) - { - fixed_t thingtop = tmthing->z + tmthing->height; - - if (front->ceilingheight < back->ceilingheight) - opentop = front->ceilingheight; - else - opentop = back->ceilingheight; - - if (front->floorheight > back->floorheight) - { - openbottom = front->floorheight; - lowfloor = back->floorheight; - } - else - { - openbottom = back->floorheight; - lowfloor = front->floorheight; - } - - // Check for fake floors in the sector. - if (front->ffloors || back->ffloors -#ifdef POLYOBJECTS - || linedef->polyobj -#endif - ) - { - ffloor_t *rover; - - fixed_t lowestceiling = opentop; - fixed_t highestfloor = openbottom; - fixed_t lowestfloor = lowfloor; - fixed_t delta1; - fixed_t delta2; - - if (!tmthing) - goto no_thing; - - thingtop = tmthing->z + tmthing->height; - - // Check for frontsector's fake floors - for (rover = front->ffloors; rover; rover = rover->next) - { - if (!(rover->flags & FF_EXISTS) || !(((rover->flags & FF_BLOCKPLAYER) && tmthing->player) - || ((rover->flags & FF_BLOCKOTHERS) && !tmthing->player))) continue; - - delta1 = abs(tmthing->z - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2))); - delta2 = abs(thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2))); - if (*rover->bottomheight < lowestceiling && delta1 >= delta2) - { - if (!(rover->flags & FF_PLATFORM)) - lowestceiling = *rover->bottomheight; - } - if (*rover->topheight < highestfloor && delta1 >= delta2) - { - if (!(rover->flags & FF_REVERSEPLATFORM)) - lowestceiling = *rover->topheight; - } - - if (*rover->topheight > highestfloor && delta1 < delta2) - highestfloor = *rover->topheight; - else if (*rover->topheight > lowestfloor && delta1 < delta2) - lowestfloor = *rover->topheight; - } - - // Check for backsectors fake floors - for (rover = back->ffloors; rover; rover = rover->next) - { - if (!(rover->flags & FF_EXISTS) || !(((rover->flags & FF_BLOCKPLAYER) && tmthing->player) - || ((rover->flags & FF_BLOCKOTHERS) && !tmthing->player))) continue; - - delta1 = abs(tmthing->z - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2))); - delta2 = abs(thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2))); - if (*rover->bottomheight < lowestceiling && delta1 >= delta2) - { - if (!(rover->flags & FF_PLATFORM)) - lowestceiling = *rover->bottomheight; - } - if (*rover->topheight < highestfloor && delta1 >= delta2) - { - if (!(rover->flags & FF_REVERSEPLATFORM)) - lowestceiling = *rover->topheight; - } - - if (*rover->topheight > highestfloor && delta1 < delta2) - highestfloor = *rover->topheight; - else if (*rover->topheight > lowestfloor && delta1 < delta2) - lowestfloor = *rover->topheight; - } - -#ifdef POLYOBJECTS - // Treat polyobj's backsector like a 3D Floor - if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) - { - const sector_t *polysec = linedef->backsector; - - delta1 = abs(tmthing->z - (polysec->floorheight + ((polysec->ceilingheight - polysec->floorheight)/2))); - delta2 = abs(thingtop - (polysec->floorheight + ((polysec->ceilingheight - polysec->floorheight)/2))); - if (polysec->floorheight < lowestceiling && delta1 >= delta2) - lowestceiling = polysec->floorheight; - - if (polysec->ceilingheight > highestfloor && delta1 < delta2) - highestfloor = polysec->ceilingheight; - else if (polysec->ceilingheight > lowestfloor && delta1 < delta2) - lowestfloor = polysec->ceilingheight; - } -#endif - - if (highestfloor > openbottom) - openbottom = highestfloor; - - if (lowestceiling < opentop) - opentop = lowestceiling; - - if (lowestfloor > lowfloor) - lowfloor = lowestfloor; - } - openrange = opentop - openbottom; - return; - } - if (front->ceilingheight < back->ceilingheight) + { opentop = front->ceilingheight; + highceiling = back->ceilingheight; + } else + { opentop = back->ceilingheight; + highceiling = front->ceilingheight; + } if (front->floorheight > back->floorheight) { @@ -544,7 +516,109 @@ void P_LineOpening(line_t *linedef) lowfloor = front->floorheight; } -no_thing: + if (tmthing) + { + fixed_t thingtop = tmthing->z + tmthing->height; + + // Check for fake floors in the sector. + if (front->ffloors || back->ffloors +#ifdef POLYOBJECTS + || linedef->polyobj +#endif + ) + { + ffloor_t *rover; + + fixed_t highestceiling = highceiling; + fixed_t lowestceiling = opentop; + fixed_t highestfloor = openbottom; + fixed_t lowestfloor = lowfloor; + fixed_t delta1, delta2; + + // Check for frontsector's fake floors + for (rover = front->ffloors; rover; rover = rover->next) + { + if (!(rover->flags & FF_EXISTS) || !(((rover->flags & FF_BLOCKPLAYER) && tmthing->player) + || ((rover->flags & FF_BLOCKOTHERS) && !tmthing->player))) continue; + + delta1 = abs(tmthing->z - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2))); + delta2 = abs(thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2))); + + if (delta1 >= delta2 && !(rover->flags & FF_PLATFORM)) // thing is below FOF + { + if (*rover->bottomheight < lowestceiling) + lowestceiling = *rover->bottomheight; + else if (*rover->bottomheight < highestceiling) + highestceiling = *rover->bottomheight; + } + + if (delta1 < delta2 && !(rover->flags & FF_REVERSEPLATFORM)) // thing is above FOF + { + if (*rover->topheight > highestfloor) + highestfloor = *rover->topheight; + else if (*rover->topheight > lowestfloor) + lowestfloor = *rover->topheight; + } + } + + // Check for backsectors fake floors + for (rover = back->ffloors; rover; rover = rover->next) + { + if (!(rover->flags & FF_EXISTS) || !(((rover->flags & FF_BLOCKPLAYER) && tmthing->player) + || ((rover->flags & FF_BLOCKOTHERS) && !tmthing->player))) continue; + + delta1 = abs(tmthing->z - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2))); + delta2 = abs(thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2))); + + if (delta1 >= delta2 && !(rover->flags & FF_PLATFORM)) // thing is below FOF + { + if (*rover->bottomheight < lowestceiling) + lowestceiling = *rover->bottomheight; + else if (*rover->bottomheight < highestceiling) + highestceiling = *rover->bottomheight; + } + + if (delta1 < delta2 && !(rover->flags & FF_REVERSEPLATFORM)) // thing is above FOF + { + if (*rover->topheight > highestfloor) + highestfloor = *rover->topheight; + else if (*rover->topheight > lowestfloor) + lowestfloor = *rover->topheight; + } + } + +#ifdef POLYOBJECTS + // Treat polyobj's backsector like a 3D Floor + if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) + { + const sector_t *polysec = linedef->backsector; + + delta1 = abs(tmthing->z - (polysec->floorheight + ((polysec->ceilingheight - polysec->floorheight)/2))); + delta2 = abs(thingtop - (polysec->floorheight + ((polysec->ceilingheight - polysec->floorheight)/2))); + if (polysec->floorheight < lowestceiling && delta1 >= delta2) + lowestceiling = polysec->floorheight; + else if (polysec->floorheight < highestceiling && delta1 >= delta2) + highestceiling = polysec->floorheight; + + if (polysec->ceilingheight > highestfloor && delta1 < delta2) + highestfloor = polysec->ceilingheight; + else if (polysec->ceilingheight > lowestfloor && delta1 < delta2) + lowestfloor = polysec->ceilingheight; + } +#endif + if (highestceiling < highceiling) + highceiling = highestceiling; + + if (highestfloor > openbottom) + openbottom = highestfloor; + + if (lowestceiling < opentop) + opentop = lowestceiling; + + if (lowestfloor > lowfloor) + lowfloor = lowestfloor; + } + } openrange = opentop - openbottom; } @@ -704,11 +778,15 @@ void P_SetThingPosition(mobj_t *thing) // Allows you to 'step' on a new linedef exec when the previous // sector's floor is the same height. - if (thing->player && oldsec != NULL && thing->subsector - && oldsec != thing->subsector->sector - && thing->z <= thing->subsector->sector->floorheight) + if (thing->player && oldsec != NULL && thing->subsector && oldsec != thing->subsector->sector) { - thing->eflags |= MFE_JUSTSTEPPEDDOWN; + if (thing->eflags & MFE_VERTICALFLIP) + { + if (thing->z + thing->height >= thing->subsector->sector->ceilingheight) + thing->eflags |= MFE_JUSTSTEPPEDDOWN; + } + else if (thing->z <= thing->subsector->sector->floorheight) + thing->eflags |= MFE_JUSTSTEPPEDDOWN; } } diff --git a/src/p_maputl.h b/src/p_maputl.h index 4fa71d14e..66f7db2db 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -43,6 +43,7 @@ boolean P_PathTraverse(fixed_t px1, fixed_t py1, fixed_t px2, fixed_t py2, FUNCMATH fixed_t P_AproxDistance(fixed_t dx, fixed_t dy); void P_ClosestPointOnLine(fixed_t x, fixed_t y, line_t *line, vertex_t *result); +void P_ClosestPointOnLine3D(fixed_t x, fixed_t y, fixed_t z, line_t *line, vertex_t *result); INT32 P_PointOnLineSide(fixed_t x, fixed_t y, line_t *line); void P_MakeDivline(line_t *li, divline_t *dl); void P_CameraLineOpening(line_t *plinedef); @@ -53,7 +54,7 @@ void P_SetPrecipitationThingPosition(precipmobj_t *thing); void P_CreatePrecipSecNodeList(precipmobj_t *thing, fixed_t x,fixed_t y); boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y); -extern fixed_t opentop, openbottom, openrange, lowfloor; +extern fixed_t opentop, openbottom, openrange, lowfloor, highceiling; void P_LineOpening(line_t *plinedef); diff --git a/src/p_mobj.c b/src/p_mobj.c index eaf57e57d..b4db48f20 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -706,6 +706,45 @@ boolean P_InsideANonSolidFFloor(mobj_t *mobj, ffloor_t *rover) return true; } +static void P_PlayerFlip(mobj_t *mo) +{ + if (!mo->player) + return; + + G_GhostAddFlip(); + // Flip aiming to match! + + if (mo->player->pflags & PF_NIGHTSMODE) // NiGHTS doesn't use flipcam + { + if (mo->tracer) + mo->tracer->eflags ^= MFE_VERTICALFLIP; + } + else if (mo->player->pflags & PF_FLIPCAM) + { + mo->player->aiming = InvAngle(mo->player->aiming); + if (mo->player-players == displayplayer) + { + localaiming = mo->player->aiming; + if (camera.chase) { + camera.aiming = InvAngle(camera.aiming); + camera.z = mo->z - camera.z + mo->z; + if (mo->eflags & MFE_VERTICALFLIP) + camera.z += FixedMul(20*FRACUNIT, mo->scale); + } + } + else if (mo->player-players == secondarydisplayplayer) + { + localaiming2 = mo->player->aiming; + if (camera2.chase) { + camera2.aiming = InvAngle(camera2.aiming); + camera2.z = mo->z - camera2.z + mo->z; + if (mo->eflags & MFE_VERTICALFLIP) + camera2.z += FixedMul(20*FRACUNIT, mo->scale); + } + } + } +} + // // P_CheckGravity // @@ -718,10 +757,13 @@ void P_CheckGravity(mobj_t *mo, boolean affect) fixed_t gravityadd = 0; boolean no3dfloorgrav = true; // Custom gravity boolean goopgravity = false; + boolean wasflip; I_Assert(mo != NULL); I_Assert(!P_MobjWasRemoved(mo)); + wasflip = (mo->eflags & MFE_VERTICALFLIP) != 0; + if (mo->type != MT_SPINFIRE) mo->eflags &= ~MFE_VERTICALFLIP; @@ -793,10 +835,7 @@ void P_CheckGravity(mobj_t *mo, boolean affect) if (bits & 1) { gravityadd = -gravityadd; - if (mo->eflags & MFE_VERTICALFLIP) - mo->eflags &= ~MFE_VERTICALFLIP; - else - mo->eflags |= MFE_VERTICALFLIP; + mo->eflags ^= MFE_VERTICALFLIP; } } } @@ -858,6 +897,9 @@ void P_CheckGravity(mobj_t *mo, boolean affect) if (affect) mo->momz += FixedMul(gravityadd, mo->scale); + if (mo->player && !!(mo->eflags & MFE_VERTICALFLIP) != wasflip) + P_PlayerFlip(mo); + if (mo->type == MT_SKIM && mo->z + mo->momz <= mo->watertop && mo->z >= mo->watertop) { mo->momz = 0; @@ -921,19 +963,26 @@ static void P_XYFriction(mobj_t *mo, fixed_t oldx, fixed_t oldy) player = mo->player; if (player) // valid only if player avatar { - if (abs(player->rmomx) < FixedMul(STOPSPEED, mo->scale) - && abs(player->rmomy) < FixedMul(STOPSPEED, mo->scale) - && (!(player->cmd.forwardmove && !(twodlevel || (player->mo->flags2 & MF2_TWOD))) && !player->cmd.sidemove && !(player->pflags & PF_SPINNING))) + // spinning friction + if (player->pflags & PF_SPINNING && (player->rmomx || player->rmomy) && !(player->pflags & PF_STARTDASH)) + { + const fixed_t ns = FixedDiv(549*FRICTION,500*FRACUNIT); + mo->momx = FixedMul(mo->momx, ns); + mo->momy = FixedMul(mo->momy, ns); + } + else if (abs(player->rmomx) < FixedMul(STOPSPEED, mo->scale) + && abs(player->rmomy) < FixedMul(STOPSPEED, mo->scale) + && (!(player->cmd.forwardmove && !(twodlevel || mo->flags2 & MF2_TWOD)) && !player->cmd.sidemove && !(player->pflags & PF_SPINNING))) { // if in a walking frame, stop moving - if (player && player->panim == PA_WALK) - P_SetPlayerMobjState(player->mo, S_PLAY_STND); + if (player->panim == PA_WALK) + P_SetPlayerMobjState(mo, S_PLAY_STND); mo->momx = player->cmomx; mo->momy = player->cmomy; } else { - if ((oldx == mo->x) && (oldy == mo->y)) // didn't go anywhere + if (oldx == mo->x && oldy == mo->y) // didn't go anywhere { mo->momx = FixedMul(mo->momx, ORIG_FRICTION); mo->momy = FixedMul(mo->momy, ORIG_FRICTION); @@ -944,17 +993,6 @@ static void P_XYFriction(mobj_t *mo, fixed_t oldx, fixed_t oldy) mo->momy = FixedMul(mo->momy, mo->friction); } - if (mo->momx || mo->momy) - { - INT32 direction = P_GetPlayerControlDirection(player); - - if (direction == 2) - { - mo->momx >>= 1; - mo->momy >>= 1; - } - } - mo->friction = ORIG_FRICTION; } } @@ -1110,17 +1148,17 @@ void P_XYMovement(mobj_t *mo) oldy = mo->y; // Pushables can break some blocks - if (CheckForBustableBlocks && (mo->flags & MF_PUSHABLE)) + if (CheckForBustableBlocks && mo->flags & MF_PUSHABLE) P_PushableCheckBustables(mo); if (!P_TryMove(mo, mo->x + xmove, mo->y + ymove, true) && !tmsprung) { // blocked move - if (mo->player) { + if (player) { moved = false; - if (mo->player->bot) - B_MoveBlocked(mo->player); + if (player->bot) + B_MoveBlocked(player); } if (mo->flags & MF_BOUNCE) @@ -1170,12 +1208,16 @@ void P_XYMovement(mobj_t *mo) return; } } - else if ((mo->player) || (mo->flags & MF_SLIDEME) - || (mo->flags & MF_PUSHABLE)) + else if (player || mo->flags & (MF_SLIDEME|MF_PUSHABLE)) { // try to slide along it P_SlideMove(mo); xmove = ymove = 0; } + else if (mo->type == MT_SPINFIRE) + { + P_RemoveMobj(mo); + return; + } else if (mo->flags & MF_MISSILE) { // explode a missile @@ -1194,9 +1236,7 @@ void P_XYMovement(mobj_t *mo) //SPLAT TEST ---------------------------------------------------------- #ifdef WALLSPLATS if (blockingline && mo->type != MT_REDRING && mo->type != MT_FIREBALL - && !(mo->flags2 & MF2_AUTOMATIC) && !(mo->flags2 & MF2_RAILRING) - && !(mo->flags2 & MF2_BOUNCERING) && !(mo->flags2 & MF2_EXPLOSION) - && !(mo->flags2 & MF2_SCATTER)) + && !(mo->flags2 & (MF2_AUTOMATIC|MF2_RAILRING|MF2_BOUNCERING|MF2_EXPLOSION|MF2_SCATTER))) // set by last P_TryMove() that failed { divline_t divl; @@ -1221,7 +1261,7 @@ void P_XYMovement(mobj_t *mo) else mo->momx = mo->momy = 0; } - else if (mo->player) + else if (player) moved = true; if (P_MobjWasRemoved(mo)) // MF_SPECIAL touched a player! O_o;; @@ -1230,13 +1270,13 @@ void P_XYMovement(mobj_t *mo) // Check the gravity status. P_CheckGravity(mo, false); - if (mo->player && !moved && (mo->player->pflags & PF_NIGHTSMODE) && mo->target) + if (player && !moved && player->pflags & PF_NIGHTSMODE && mo->target) { angle_t fa; P_UnsetThingPosition(mo); - mo->player->angle_pos = mo->player->old_angle_pos; - mo->player->speed = FixedMul(mo->player->speed, 4*FRACUNIT/5); + player->angle_pos = player->old_angle_pos; + player->speed = FixedMul(player->speed, 4*FRACUNIT/5); if (player->flyangle >= 0 && player->flyangle < 90) player->flyangle = 135; else if (player->flyangle >= 90 && player->flyangle < 180) @@ -1264,28 +1304,19 @@ void P_XYMovement(mobj_t *mo) P_SetThingPosition(mo); } - if ((mo->flags & MF_MISSILE) || (mo->flags2 & MF2_SKULLFLY) || mo->type == MT_SHELL || mo->type == MT_VULTURE) + if (mo->flags & MF_NOCLIPHEIGHT) + return; // no frictions for objects that can pass through floors + + if (mo->flags & MF_MISSILE || mo->flags2 & MF2_SKULLFLY || mo->type == MT_SHELL || mo->type == MT_VULTURE) return; // no friction for missiles ever - if (mo->player && mo->player->homing) // no friction for homing + if (player && player->homing) // no friction for homing return; if (((!(mo->eflags & MFE_VERTICALFLIP) && mo->z > mo->floorz) || (mo->eflags & MFE_VERTICALFLIP && mo->z+mo->height < mo->ceilingz)) - && !(mo->player && (mo->player->pflags & PF_SLIDING))) + && !(player && player->pflags & PF_SLIDING)) return; // no friction when airborne - // spinning friction - if (player) - { - if ((player->pflags & PF_SPINNING) && (player->rmomx || player->rmomy) && !(player->pflags & PF_STARTDASH)) - { - const fixed_t ns = FixedDiv(549*FRICTION,500*FRACUNIT); - mo->momx = FixedMul(mo->momx, ns); - mo->momy = FixedMul(mo->momy, ns); - return; - } - } - P_XYFriction(mo, oldx, oldy); } @@ -1311,9 +1342,12 @@ static void P_SceneryXYMovement(mobj_t *mo) if (!P_SceneryTryMove(mo, mo->x + mo->momx, mo->y + mo->momy)) P_SlideMove(mo); - if (mo->z > mo->floorz) + if ((!(mo->eflags & MFE_VERTICALFLIP) && mo->z > mo->floorz) || (mo->eflags & MFE_VERTICALFLIP && mo->z+mo->height < mo->ceilingz)) return; // no friction when airborne + if (mo->flags & MF_NOCLIPHEIGHT) + return; // no frictions for objects that can pass through floors + P_SceneryXYFriction(mo, oldx, oldy); } @@ -1379,9 +1413,9 @@ static void P_RingZMovement(mobj_t *mo) } else if (mo->z + mo->height > mo->ceilingz && !(mo->flags & MF_NOCLIPHEIGHT)) { - mo->momz = 0; - mo->z = mo->ceilingz - mo->height; + + mo->momz = 0; } } @@ -1654,14 +1688,22 @@ static boolean P_ZMovement(mobj_t *mo) } // clip movement - if (mo->z <= mo->floorz && !(mo->flags & MF_NOCLIPHEIGHT)) + if (((mo->z <= mo->floorz && !(mo->eflags & MFE_VERTICALFLIP)) + || (mo->z + mo->height >= mo->ceilingz && mo->eflags & MFE_VERTICALFLIP)) + && !(mo->flags & MF_NOCLIPHEIGHT)) { + if (mo->eflags & MFE_VERTICALFLIP) + mo->z = mo->ceilingz - mo->height; + else + mo->z = mo->floorz; + // hit the floor if (mo->type == MT_FIREBALL) // special case for the fireball - mo->momz = FixedMul(5*FRACUNIT, mo->scale); + mo->momz = P_MobjFlip(mo)*FixedMul(5*FRACUNIT, mo->scale); + else if (mo->type == MT_SPINFIRE) // elemental shield fire is another exception here + ; else if (mo->flags & MF_MISSILE) { - mo->z = mo->floorz; if (!(mo->flags & MF_NOCLIP)) { // This is a really ugly hard-coded hack to prevent grenades @@ -1672,7 +1714,7 @@ static boolean P_ZMovement(mobj_t *mo) if (mo->flags & MF_GRENADEBOUNCE) { // Going down? (Or up in reverse gravity?) - if (mo->momz*P_MobjFlip(mo) < 0) + if (P_MobjFlip(mo)*mo->momz < 0) { // If going slower than a fracunit, just stop. if (abs(mo->momz) < FixedMul(FRACUNIT, mo->scale)) @@ -1685,7 +1727,7 @@ static boolean P_ZMovement(mobj_t *mo) } // Otherwise bounce up at half speed. else - mo->momz = -FixedMul(mo->momz, FRACUNIT/2); + mo->momz = -mo->momz/2; S_StartSound(mo, mo->info->activesound); } } @@ -1693,9 +1735,14 @@ static boolean P_ZMovement(mobj_t *mo) else { // Don't explode on the sky! - if (mo->subsector->sector->floorpic == skyflatnum + if (!(mo->eflags & MFE_VERTICALFLIP) + && mo->subsector->sector->floorpic == skyflatnum && mo->subsector->sector->floorheight == mo->floorz) P_RemoveMobj(mo); + else if (mo->eflags & MFE_VERTICALFLIP + && mo->subsector->sector->ceilingpic == skyflatnum + && mo->subsector->sector->ceilingheight == mo->ceilingz) + P_RemoveMobj(mo); else P_ExplodeMissile(mo); return false; @@ -1703,28 +1750,15 @@ static boolean P_ZMovement(mobj_t *mo) } } - if (mo->flags2 & MF2_SKULLFLY) // the skull slammed into something - mo->momz = -mo->momz; - - if (mo->momz < 0) // falling + if (P_MobjFlip(mo)*mo->momz < 0) // falling { - // set it once and not continuously - if (tmfloorthing) - { - // Bouncing boxes - if (tmfloorthing->z > tmfloorthing->floorz) - { - if ((tmfloorthing->flags & MF_MONITOR) || (tmfloorthing->flags & MF_PUSHABLE)) - mo->momz = FixedMul(4*FRACUNIT, mo->scale); - } - } - if (!tmfloorthing || tmfloorthing->flags & MF_PUSHABLE - || tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER) - { - if (!tmfloorthing || mo->momz) - mo->eflags |= MFE_JUSTHITFLOOR; - } + if (!tmfloorthing || tmfloorthing->flags & (MF_PUSHABLE|MF_MONITOR) + || tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER) + mo->eflags |= MFE_JUSTHITFLOOR; + if (mo->flags2 & MF2_SKULLFLY) // the skull slammed into something + mo->momz = -mo->momz; + else // Flingrings bounce if (mo->type == MT_FLINGRING || mo->type == MT_FLINGCOIN @@ -1733,9 +1767,7 @@ static boolean P_ZMovement(mobj_t *mo) || mo->type == MT_BIGTUMBLEWEED || mo->type == MT_LITTLETUMBLEWEED || mo->type == MT_CANNONBALLDECOR - || mo->type == MT_FALLINGROCK - || ((mo->eflags & MFE_VERTICALFLIP) && mo->type == MT_REDFLAG) - || ((mo->eflags & MFE_VERTICALFLIP) && mo->type == MT_BLUEFLAG)) + || mo->type == MT_FALLINGROCK) { if (maptol & TOL_NIGHTS) mo->momz = -FixedDiv(mo->momz, 10*FRACUNIT); @@ -1756,7 +1788,7 @@ static boolean P_ZMovement(mobj_t *mo) else { // If deafed, give the tumbleweed another random kick if it runs out of steam. - mo->momz += FixedMul(6*FRACUNIT, mo->scale); + mo->momz += P_MobjFlip(mo)*FixedMul(6*FRACUNIT, mo->scale); if (P_Random() & 1) mo->momx += FixedMul(6*FRACUNIT, mo->scale); @@ -1776,7 +1808,7 @@ static boolean P_ZMovement(mobj_t *mo) } else if (mo->type == MT_FALLINGROCK) { - if (mo->momz > FixedMul(2*FRACUNIT, mo->scale)) + if (P_MobjFlip(mo)*mo->momz > FixedMul(2*FRACUNIT, mo->scale)) S_StartSound(mo, mo->info->activesound + P_RandomKey(mo->info->mass)); mo->momz /= 2; // Rocks not so bouncy @@ -1796,14 +1828,15 @@ static boolean P_ZMovement(mobj_t *mo) mo->momz = 0; } } - else if (tmfloorthing && (tmfloorthing->flags & MF_PUSHABLE + else if (tmfloorthing && (tmfloorthing->flags & (MF_PUSHABLE|MF_MONITOR) || tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER)) mo->momz = tmfloorthing->momz; else if (!tmfloorthing) mo->momz = 0; } - - mo->z = mo->floorz; + else if (tmfloorthing && (tmfloorthing->flags & (MF_PUSHABLE|MF_MONITOR) + || tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER)) + mo->momz = tmfloorthing->momz; if (mo->type == MT_STEAM) return true; @@ -1816,15 +1849,52 @@ static boolean P_ZMovement(mobj_t *mo) P_CheckGravity(mo, true); } - if (mo->z + mo->height > mo->ceilingz && !(mo->flags & MF_NOCLIPHEIGHT)) + if (((mo->z + mo->height > mo->ceilingz && !(mo->eflags & MFE_VERTICALFLIP)) + || (mo->z < mo->floorz && mo->eflags & MFE_VERTICALFLIP)) + && !(mo->flags & MF_NOCLIPHEIGHT)) { - if (mo->momz > 0) // hit the ceiling + if (mo->eflags & MFE_VERTICALFLIP) + mo->z = mo->floorz; + else + mo->z = mo->ceilingz - mo->height; + + if (mo->type == MT_SPINFIRE) + ; + else if ((mo->flags & MF_MISSILE) && !(mo->flags & MF_NOCLIP)) { - // Flingrings bounce - if ((mo->eflags & MFE_VERTICALFLIP) && (mo->type == MT_FLINGRING - || mo->type == MT_FLINGCOIN - || P_WeaponOrPanel(mo->type) - || mo->type == MT_FLINGEMERALD)) + // Hack 2: Electric Boogaloo -SH + if (mo->flags & MF_GRENADEBOUNCE) + { + if (P_MobjFlip(mo)*mo->momz >= 0) + { + mo->momz = -mo->momz; + S_StartSound(mo, mo->info->activesound); + } + } + else + { + // Don't explode on the sky! + if (!(mo->eflags & MFE_VERTICALFLIP) + && mo->subsector->sector->ceilingpic == skyflatnum + && mo->subsector->sector->ceilingheight == mo->ceilingz) + P_RemoveMobj(mo); + else if (mo->eflags & MFE_VERTICALFLIP + && mo->subsector->sector->floorpic == skyflatnum + && mo->subsector->sector->floorheight == mo->floorz) + P_RemoveMobj(mo); + else + P_ExplodeMissile(mo); + return false; + } + } + + if (P_MobjFlip(mo)*mo->momz > 0) // hit the ceiling + { + if (mo->flags2 & MF2_SKULLFLY) // the skull slammed into something + mo->momz = -mo->momz; + else + // Flags bounce + if (mo->type == MT_REDFLAG || mo->type == MT_BLUEFLAG) { if (maptol & TOL_NIGHTS) mo->momz = -FixedDiv(mo->momz, 10*FRACUNIT); @@ -1834,36 +1904,8 @@ static boolean P_ZMovement(mobj_t *mo) else mo->momz = 0; } - - mo->z = mo->ceilingz - mo->height; - - if (mo->flags2 & MF2_SKULLFLY) // the skull slammed into something - mo->momz = -mo->momz; - - - if ((mo->flags & MF_MISSILE) && !(mo->flags & MF_NOCLIP)) - { - // Hack 2: Electric Boogaloo -SH - if (mo->type == MT_THROWNGRENADE || mo->type == MT_CYBRAKDEMON_NAPALM_BOMB_LARGE) - { - if (mo->momz >= 0) - { - mo->momz = -mo->momz; - S_StartSound(mo, mo->info->activesound); - } - } - else - { - // Don't explode on the sky! - if (mo->subsector->sector->ceilingpic == skyflatnum - && mo->subsector->sector->ceilingheight == mo->ceilingz) - P_RemoveMobj(mo); - else - P_ExplodeMissile(mo); - return false; - } - } } + return true; } @@ -1945,15 +1987,19 @@ static void P_PlayerZMovement(mobj_t *mo) return; // clip movement - if (P_IsObjectOnGround(mo)) + if (P_IsObjectOnGround(mo) && !(mo->flags & MF_NOCLIPHEIGHT)) { + if (mo->eflags & MFE_VERTICALFLIP) + mo->z = mo->ceilingz - mo->height; + else + mo->z = mo->floorz; + if (mo->player && (mo->player->pflags & PF_NIGHTSMODE)) { if (mo->player->flyangle < 90 || mo->player->flyangle >= 270) - mo->player->flyangle += 90; + mo->player->flyangle += P_MobjFlip(mo)*90; else - mo->player->flyangle -= 90; - mo->z = mo->floorz; + mo->player->flyangle -= P_MobjFlip(mo)*90; mo->player->speed = FixedMul(mo->player->speed, 4*FRACUNIT/5); goto nightsdone; } @@ -1961,11 +2007,6 @@ static void P_PlayerZMovement(mobj_t *mo) if (mo->state == &states[mo->info->painstate] || mo->state == &states[S_PLAY_SUPERHIT]) P_SetPlayerMobjState(mo, S_PLAY_STND); - if (mo->eflags & MFE_VERTICALFLIP) - mo->z = mo->ceilingz - mo->height; - else - mo->z = mo->floorz; - if (P_MobjFlip(mo)*mo->momz < 0) // falling { // Squat down. Decrease viewheight for a moment after hitting the ground (hard), @@ -1975,25 +2016,10 @@ static void P_PlayerZMovement(mobj_t *mo) mo->player->deltaviewheight = (P_MobjFlip(mo)*mo->momz)>>3; // make sure momz is negative } - // set it once and not continuously - if (tmfloorthing) + if (!tmfloorthing || tmfloorthing->flags & (MF_PUSHABLE|MF_MONITOR) + || tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER) // Spin Attack { - if ((tmfloorthing->flags & MF_MONITOR) || (tmfloorthing->flags & MF_PUSHABLE) - || (tmfloorthing->flags2 & MF2_STANDONME)) - { - if (mo->player) - { - if (!(mo->player->pflags & PF_JUMPED)) - tmfloorthing = 0; - } - } - } - - if (P_IsObjectOnGround(mo) && (!tmfloorthing || tmfloorthing->flags & MF_PUSHABLE - || tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER)) // Spin Attack - { - if ((tmfloorthing && mo->momz) || !tmfloorthing) - mo->eflags |= MFE_JUSTHITFLOOR; // Spin Attack + mo->eflags |= MFE_JUSTHITFLOOR; // Spin Attack if (mo->eflags & MFE_JUSTHITFLOOR) { @@ -2055,21 +2081,22 @@ static void P_PlayerZMovement(mobj_t *mo) // Cut momentum in half when you hit the ground and // aren't pressing any controls. - if (!(mo->player->cmd.forwardmove || mo->player->cmd.sidemove) && !mo->player->cmomx && !mo->player->cmomy && !(mo->player->pflags & PF_SPINNING)) + if (!mo->player || (!(mo->player->cmd.forwardmove || mo->player->cmd.sidemove) && !mo->player->cmomx && !mo->player->cmomy && !(mo->player->pflags & PF_SPINNING))) { mo->momx = mo->momx/2; mo->momy = mo->momy/2; } } - if (mo->health) + if (mo->health && mo->player) { if (mo->player->pflags & PF_GLIDING) // ground gliding { mo->player->skidtime = TICRATE; mo->tics = -1; } - else if (mo->player->pflags & PF_JUMPED || (mo->player->pflags & (PF_SPINNING|PF_USEDOWN)) != (PF_SPINNING|PF_USEDOWN)) + else if (mo->player->pflags & PF_JUMPED || (mo->player->pflags & (PF_SPINNING|PF_USEDOWN)) != (PF_SPINNING|PF_USEDOWN) + || mo->player->powers[pw_tailsfly] || (mo->state >= &states[S_PLAY_SPC1] && mo->state <= &states[S_PLAY_SPC4])) { if (mo->player->cmomx || mo->player->cmomy) { @@ -2104,69 +2131,59 @@ static void P_PlayerZMovement(mobj_t *mo) mo->player->secondjump = 0; mo->player->glidetime = 0; mo->player->climbing = 0; + mo->player->powers[pw_tailsfly] = 0; } } if (mo->player && !(mo->player->pflags & PF_SPINNING)) mo->player->pflags &= ~PF_STARTDASH; - if (!tmfloorthing || tmfloorthing->flags & MF_PUSHABLE - || tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER) + if (tmfloorthing && (tmfloorthing->flags & (MF_PUSHABLE|MF_MONITOR) + || tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER)) + mo->momz = tmfloorthing->momz; + else if (!tmfloorthing) mo->momz = 0; } + else if (tmfloorthing && (tmfloorthing->flags & (MF_PUSHABLE|MF_MONITOR) + || tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER)) + mo->momz = tmfloorthing->momz; } else if (!(mo->flags & MF_NOGRAVITY)) // Gravity here! { - boolean wasflip; - /// \todo may not be needed (done in P_MobjThinker normally) - mo->eflags &= ~MFE_JUSTHITFLOOR; - - wasflip = (mo->eflags & MFE_VERTICALFLIP) != 0; - P_CheckGravity(mo, true); - - if ((wasflip && !(mo->eflags & MFE_VERTICALFLIP)) - || (!wasflip && (mo->eflags & MFE_VERTICALFLIP))) + if (P_IsObjectInGoop(mo) && !(mo->flags & MF_NOCLIPHEIGHT)) { - G_GhostAddFlip(); - // Flip aiming to match! - if (mo->player->pflags & PF_FLIPCAM) + if (mo->z < mo->floorz) { - mo->player->aiming = InvAngle(mo->player->aiming); - if (mo->player-players == displayplayer) - { - localaiming = mo->player->aiming; - if (camera.chase) { - camera.aiming = InvAngle(camera.aiming); - camera.z = mo->z - camera.z + mo->z; - if (mo->eflags & MFE_VERTICALFLIP) - camera.z += FixedMul(20*FRACUNIT, mo->scale); - } - } - else if (mo->player-players == secondarydisplayplayer) - { - localaiming2 = mo->player->aiming; - if (camera2.chase) { - camera2.aiming = InvAngle(camera2.aiming); - camera2.z = mo->z - camera2.z + mo->z; - if (mo->eflags & MFE_VERTICALFLIP) - camera2.z += FixedMul(20*FRACUNIT, mo->scale); - } - } + mo->z = mo->floorz; + mo->momz = 0; + } + else if (mo->z + mo->height > mo->ceilingz) + { + mo->z = mo->ceilingz - mo->height; + mo->momz = 0; } } + /// \todo may not be needed (done in P_MobjThinker normally) + mo->eflags &= ~MFE_JUSTHITFLOOR; + P_CheckGravity(mo, true); } nightsdone: - if ((mo->eflags & MFE_VERTICALFLIP && mo->z < mo->floorz) || (!(mo->eflags & MFE_VERTICALFLIP) && mo->z + mo->height > mo->ceilingz)) + if (((mo->eflags & MFE_VERTICALFLIP && mo->z < mo->floorz) || (!(mo->eflags & MFE_VERTICALFLIP) && mo->z + mo->height > mo->ceilingz)) + && !(mo->flags & MF_NOCLIPHEIGHT)) { + if (mo->eflags & MFE_VERTICALFLIP) + mo->z = mo->floorz; + else + mo->z = mo->ceilingz - mo->height; + if (mo->player && (mo->player->pflags & PF_NIGHTSMODE)) { if (mo->player->flyangle < 90 || mo->player->flyangle >= 270) - mo->player->flyangle -= 90; + mo->player->flyangle -= P_MobjFlip(mo)*90; else - mo->player->flyangle += 90; + mo->player->flyangle += P_MobjFlip(mo)*90; mo->player->flyangle %= 360; - mo->z = mo->ceilingz - mo->height; mo->player->speed = FixedMul(mo->player->speed, 4*FRACUNIT/5); } @@ -2206,11 +2223,6 @@ nightsdone: if (!(mo->player && mo->player->climbing)) mo->momz = 0; } - - if (mo->eflags & MFE_VERTICALFLIP) - mo->z = mo->floorz; - else - mo->z = mo->ceilingz - mo->height; } } @@ -2352,20 +2364,25 @@ static boolean P_SceneryZMovement(mobj_t *mo) } // clip movement - if (mo->z <= mo->floorz && !(mo->flags & MF_NOCLIPHEIGHT)) + if (((mo->z <= mo->floorz && !(mo->eflags & MFE_VERTICALFLIP)) + || (mo->z + mo->height >= mo->ceilingz && mo->eflags & MFE_VERTICALFLIP)) + && !(mo->flags & MF_NOCLIPHEIGHT)) { - mo->z = mo->floorz; + if (mo->eflags & MFE_VERTICALFLIP) + mo->z = mo->ceilingz - mo->height; + else + mo->z = mo->floorz; - if (mo->momz < 0) // falling + if (P_MobjFlip(mo)*mo->momz < 0) // falling { - if (!tmfloorthing || tmfloorthing->flags & MF_PUSHABLE + if (!tmfloorthing || tmfloorthing->flags & (MF_PUSHABLE|MF_MONITOR) || tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER) - { - if (!tmfloorthing || mo->momz) mo->eflags |= MFE_JUSTHITFLOOR; // Spin Attack - } - if (!tmfloorthing) + if (tmfloorthing && (tmfloorthing->flags & (MF_PUSHABLE|MF_MONITOR) + || tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER)) + mo->momz = tmfloorthing->momz; + else if (!tmfloorthing) mo->momz = 0; } } @@ -2377,15 +2394,17 @@ static boolean P_SceneryZMovement(mobj_t *mo) P_CheckGravity(mo, true); } - if (mo->z + mo->height > mo->ceilingz && !(mo->flags & MF_NOCLIPHEIGHT)) + if (((mo->z + mo->height > mo->ceilingz && !(mo->eflags & MFE_VERTICALFLIP)) + || (mo->z < mo->floorz && mo->eflags & MFE_VERTICALFLIP)) + && !(mo->flags & MF_NOCLIPHEIGHT)) { - if (mo->momz > 0) - { - // hit the ceiling - mo->momz = 0; - } + if (mo->eflags & MFE_VERTICALFLIP) + mo->z = mo->floorz; + else + mo->z = mo->ceilingz - mo->height; - mo->z = mo->ceilingz - mo->height; + if (P_MobjFlip(mo)*mo->momz > 0) // hit the ceiling + mo->momz = 0; } return true; @@ -2682,6 +2701,7 @@ static void P_SceneryCheckWater(mobj_t *mobj) static boolean P_CameraCheckHeat(camera_t *thiscam) { sector_t *sector; + fixed_t halfheight = thiscam->z + (thiscam->height >> 1); // see if we are in water sector = thiscam->subsector->sector; @@ -2695,17 +2715,14 @@ static boolean P_CameraCheckHeat(camera_t *thiscam) for (rover = sector->ffloors; rover; rover = rover->next) { - if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE) || rover->flags & FF_BLOCKOTHERS) - continue; - if (*rover->topheight <= thiscam->z - || *rover->bottomheight > (thiscam->z + (thiscam->height >> 1))) + if (!(rover->flags & FF_EXISTS)) continue; - if (thiscam->z + (thiscam->height >> 1) < *rover->topheight) - { - if (P_FindSpecialLineFromTag(13, rover->master->frontsector->tag, -1) != -1) - return true; - } + if (halfheight >= *rover->topheight || halfheight <= *rover->bottomheight) + continue; + + if (P_FindSpecialLineFromTag(13, rover->master->frontsector->tag, -1) != -1) + return true; } } @@ -2715,6 +2732,7 @@ static boolean P_CameraCheckHeat(camera_t *thiscam) static boolean P_CameraCheckWater(camera_t *thiscam) { sector_t *sector; + fixed_t halfheight = thiscam->z + (thiscam->height >> 1); // see if we are in water sector = thiscam->subsector->sector; @@ -2727,12 +2745,11 @@ static boolean P_CameraCheckWater(camera_t *thiscam) { if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE) || rover->flags & FF_BLOCKOTHERS) continue; - if (*rover->topheight <= thiscam->z - || *rover->bottomheight > (thiscam->z + (thiscam->height >> 1))) + + if (halfheight >= *rover->topheight || halfheight <= *rover->bottomheight) continue; - if (thiscam->z + (thiscam->height >> 1) < *rover->topheight) - return true; + return true; } } @@ -2774,13 +2791,30 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled || (thiscam == &camera2 && players[secondarydisplayplayer].mo && (players[secondarydisplayplayer].mo->flags2 & MF2_TWOD))) itsatwodlevel = true; - // Are we in water? - if (player->pflags & PF_FLIPCAM && player->mo->eflags & MFE_VERTICALFLIP) + if (player->pflags & PF_FLIPCAM && !(player->pflags & PF_NIGHTSMODE) && player->mo->eflags & MFE_VERTICALFLIP) postimg = postimg_flip; - else if (P_CameraCheckWater(thiscam)) - postimg = postimg_water; - else if (P_CameraCheckHeat(thiscam)) - postimg = postimg_heat; + else if (player->awayviewtics) + { + camera_t dummycam; + dummycam.subsector = player->awayviewmobj->subsector; + dummycam.x = player->awayviewmobj->x; + dummycam.y = player->awayviewmobj->y; + dummycam.z = player->awayviewmobj->z; + dummycam.height = 40*FRACUNIT; // alt view height is 20*FRACUNIT + // Are we in water? + if (P_CameraCheckWater(&dummycam)) + postimg = postimg_water; + else if (P_CameraCheckHeat(&dummycam)) + postimg = postimg_heat; + } + else + { + // Are we in water? + if (P_CameraCheckWater(thiscam)) + postimg = postimg_water; + else if (P_CameraCheckHeat(thiscam)) + postimg = postimg_heat; + } if (postimg != postimg_none) { @@ -2876,12 +2910,10 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled static void P_PlayerMobjThinker(mobj_t *mobj) { msecnode_t *node; - boolean wasflip; I_Assert(mobj != NULL); I_Assert(!P_MobjWasRemoved(mobj)); - wasflip = (mobj->eflags & MFE_VERTICALFLIP) != 0; P_MobjCheckWater(mobj); // momentum movement @@ -2917,36 +2949,6 @@ static void P_PlayerMobjThinker(mobj_t *mobj) else P_TryMove(mobj, mobj->x, mobj->y, true); - if ((wasflip && !(mobj->eflags & MFE_VERTICALFLIP)) - || (!wasflip && (mobj->eflags & MFE_VERTICALFLIP))) - { // Flip aiming to match! - G_GhostAddFlip(); - if (mobj->player->pflags & PF_FLIPCAM) - { - mobj->player->aiming = InvAngle(mobj->player->aiming); - if (mobj->player-players == displayplayer) - { - localaiming = mobj->player->aiming; - if (camera.chase) { - camera.aiming = InvAngle(camera.aiming); - camera.z = mobj->z - camera.z + mobj->z; - if (mobj->eflags & MFE_VERTICALFLIP) - camera.z += FixedMul(20*FRACUNIT, mobj->scale); - } - } - else if (mobj->player-players == secondarydisplayplayer) - { - localaiming2 = mobj->player->aiming; - if (camera2.chase) { - camera2.aiming = InvAngle(camera2.aiming); - camera2.z = mobj->z - camera2.z + mobj->z; - if (mobj->eflags & MFE_VERTICALFLIP) - camera2.z += FixedMul(20*FRACUNIT, mobj->scale); - } - } - } - } - if (!(netgame && mobj->player && mobj->player->spectator)) { // Crumbling platforms @@ -3020,7 +3022,7 @@ static void P_PlayerMobjThinker(mobj_t *mobj) if (!(mobj->eflags & MFE_ONGROUND) || mobj->momz || ((mobj->eflags & MFE_VERTICALFLIP) && mobj->z + mobj->height != mobj->ceilingz) || (!(mobj->eflags & MFE_VERTICALFLIP) && mobj->z != mobj->floorz) - || ((mobj->eflags & (MFE_UNDERWATER|MFE_GOOWATER)) == (MFE_UNDERWATER|MFE_GOOWATER))) + || P_IsObjectInGoop(mobj)) { P_PlayerZMovement(mobj); P_CheckPosition(mobj, mobj->x, mobj->y); // Need this to pick up objects! @@ -3030,8 +3032,18 @@ static void P_PlayerMobjThinker(mobj_t *mobj) } else { - mobj->player->jumping = 0; - mobj->player->pflags &= ~PF_JUMPED; + if (mobj->player) + { + mobj->player->jumping = 0; + mobj->player->pflags &= ~PF_JUMPED; + if (mobj->player->secondjump || mobj->player->powers[pw_tailsfly]) + { + mobj->player->secondjump = 0; + mobj->player->powers[pw_tailsfly] = 0; + P_SetPlayerMobjState(mobj, S_PLAY_RUN1); + } + } + mobj->pmomz = 0; mobj->eflags &= ~MFE_JUSTHITFLOOR; } @@ -3503,9 +3515,30 @@ static void P_Boss3Thinker(mobj_t *mobj) if (!mobj->reactiontime && mobj->health <= mobj->info->damage) { // Spawn pinch dummies from the center when we're leaving it. + thinker_t *th; + mobj_t *mo2; mobj_t *dummy; SINT8 way = mobj->threshold - 1; // 0 through 4. SINT8 way2; + + i = 0; // reset i to 0 so we can check how many clones we've removed + + // scan the thinkers to make sure all the old pinch dummies are gone before making new ones + // this can happen if the boss was hurt earlier than expected + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + mo2 = (mobj_t *)th; + if (mo2->type == (mobjtype_t)mobj->info->mass && mo2->tracer == mobj) + { + P_RemoveMobj(mo2); + i++; + } + if (i == 2) // we've already removed 2 of these, let's stop now + break; + } way = (way + P_RandomRange(1,3)) % 5; // dummy 1 at one of the first three options after eggmobile dummy = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->info->mass); @@ -4864,15 +4897,15 @@ static void P_MoveHoop(mobj_t *mobj) TVector v; TVector *res; fixed_t finalx, finaly, finalz; - fixed_t mthingx, mthingy, mthingz; + fixed_t x, y, z; //I_Assert(mobj->target != NULL); if (!mobj->target) /// \todo DEBUG ME! Target was P_RemoveMobj'd at some point, and therefore no longer valid! return; - mthingx = mobj->target->x; - mthingy = mobj->target->y; - mthingz = mobj->target->z+mobj->target->height/2; + x = mobj->target->x; + y = mobj->target->y; + z = mobj->target->z+mobj->target->height/2; // Make the sprite travel towards the center of the hoop v[0] = FixedMul(FINECOSINE(fa),fuse); @@ -4885,9 +4918,9 @@ static void P_MoveHoop(mobj_t *mobj) res = VectorMatrixMultiply(v, *RotateZMatrix(FixedAngle(mobj->target->movecount*FRACUNIT))); M_Memcpy(&v, res, sizeof (v)); - finalx = mthingx + v[0]; - finaly = mthingy + v[1]; - finalz = mthingz + v[2]; + finalx = x + v[0]; + finaly = y + v[1]; + finalz = z + v[2]; P_UnsetThingPosition(mobj); mobj->x = finalx; @@ -5068,6 +5101,7 @@ void P_SetScale(mobj_t *mobj, fixed_t newscale) { G_GhostAddScale(newscale); player->viewheight = FixedMul(FixedDiv(player->viewheight, oldscale), newscale); // Nonono don't calculate viewheight elsewhere, this is the best place for it! + player->dashspeed = FixedMul(FixedDiv(player->dashspeed, oldscale), newscale); // Prevents the player from having to re-charge up spindash if the player grew in size } } @@ -5887,11 +5921,17 @@ void P_MobjThinker(mobj_t *mobj) /// \todo Have the player's dead body completely finish its animation even if they've already respawned. if (!(mobj->flags2 & MF2_DONTDRAW)) { - if (mobj->player && mobj->player->deadtimer > 3*TICRATE) + if (!mobj->fuse) { // Go away. /// \todo Actually go ahead and remove mobj completely, and fix any bugs and crashes doing this creates. Chasecam should stop moving, and F12 should never return to it. mobj->momz = 0; - mobj->flags2 |= MF2_DONTDRAW; + if (mobj->player) + mobj->flags2 |= MF2_DONTDRAW; + else // safe to remove, nobody's going to complain! + { + P_RemoveMobj(mobj); + return; + } } else // Apply gravity to fall downwards. P_SetObjectMomZ(mobj, -2*FRACUNIT/3, true); @@ -6360,7 +6400,7 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->state != &states[S_SHELL]) { - mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->x+mobj->momx, mobj->y+mobj->momy); + mobj->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy); P_InstaThrust(mobj, mobj->angle, FixedMul(mobj->info->speed, mobj->scale)); } break; @@ -6426,7 +6466,7 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->eflags & MFE_VERTICALFLIP) mobj->z = mobj->ceilingz - mobj->height; else - mobj->z = mobj->floorz+1; + mobj->z = mobj->floorz; // THERE IS NO BREAK HERE ON PURPOSE default: // check mobj against possible water content, before movement code @@ -6773,6 +6813,8 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s case MT_NIGHTSCORE: P_RemoveMobj(mobj); return; + case MT_PLAYER: + break; // don't remove default: P_SetMobjState(mobj, mobj->info->xdeathstate); // will remove the mobj if S_NULL. break; @@ -6797,7 +6839,7 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s if (!(mobj->eflags & MFE_ONGROUND) || mobj->momz || ((mobj->eflags & MFE_VERTICALFLIP) && mobj->z + mobj->height != mobj->ceilingz) || (!(mobj->eflags & MFE_VERTICALFLIP) && mobj->z != mobj->floorz) - || ((mobj->eflags & (MFE_UNDERWATER|MFE_GOOWATER)) == (MFE_UNDERWATER|MFE_GOOWATER))) + || P_IsObjectInGoop(mobj)) { if (!P_ZMovement(mobj)) return; // mobj was removed @@ -6807,6 +6849,17 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s } else { + if (mobj->player) + { + mobj->player->jumping = 0; + mobj->player->pflags &= ~PF_JUMPED; + if (mobj->player->secondjump || mobj->player->powers[pw_tailsfly]) + { + mobj->player->secondjump = 0; + mobj->player->powers[pw_tailsfly] = 0; + P_SetPlayerMobjState(mobj, S_PLAY_RUN1); + } + } mobj->pmomz = 0; // to prevent that weird rocketing gargoyle bug mobj->eflags &= ~MFE_JUSTHITFLOOR; } @@ -6995,7 +7048,7 @@ void P_SceneryThinker(mobj_t *mobj) if (!(mobj->eflags & MFE_ONGROUND) || mobj->momz || ((mobj->eflags & MFE_VERTICALFLIP) && mobj->z + mobj->height != mobj->ceilingz) || (!(mobj->eflags & MFE_VERTICALFLIP) && mobj->z != mobj->floorz) - || ((mobj->eflags & (MFE_UNDERWATER|MFE_GOOWATER)) == (MFE_UNDERWATER|MFE_GOOWATER))) + || P_IsObjectInGoop(mobj)) { if (!P_SceneryZMovement(mobj)) return; // mobj was removed @@ -7007,6 +7060,17 @@ void P_SceneryThinker(mobj_t *mobj) } else { + if (mobj->player) + { + mobj->player->jumping = 0; + mobj->player->pflags &= ~PF_JUMPED; + if (mobj->player->secondjump || mobj->player->powers[pw_tailsfly]) + { + mobj->player->secondjump = 0; + mobj->player->powers[pw_tailsfly] = 0; + P_SetPlayerMobjState(mobj, S_PLAY_RUN1); + } + } mobj->pmomz = 0; // to prevent that weird rocketing gargoyle bug mobj->eflags &= ~MFE_JUSTHITFLOOR; } @@ -7101,12 +7165,22 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) mobj->z = z; #ifdef HAVE_BLUA - if (!LUAh_MobjSpawn(mobj)) + // DANGER! This can cause P_SpawnMobj to return NULL! + // Avoid using P_RemoveMobj on the newly created mobj in "MobjSpawn" Lua hooks! + if (LUAh_MobjSpawn(mobj)) + { + if (P_MobjWasRemoved(mobj)) + return NULL; + } + else if (P_MobjWasRemoved(mobj)) + return NULL; + else #endif switch (mobj->type) { case MT_CYBRAKDEMON_NAPALM_BOMB_LARGE: mobj->fuse = mobj->info->mass; + break; case MT_BLACKEGGMAN: { mobj_t *spawn = P_SpawnMobj(mobj->x, mobj->z, mobj->z+mobj->height-16*FRACUNIT, MT_BLACKEGGMAN_HELPER); @@ -7230,7 +7304,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) astate = st; #endif st->action.acp1(mobj); - // DANGER! This is the ONLY way for P_SpawnMobj to return NULL! + // DANGER! This can cause P_SpawnMobj to return NULL! // Avoid using MF_RUNSPAWNFUNC on mobjs whose spawn state expects target or tracer to already be set! if (P_MobjWasRemoved(mobj)) return NULL; @@ -7653,6 +7727,7 @@ void P_PrecipitationEffects(void) void P_RespawnSpecials(void) { fixed_t x, y, z; + subsector_t *ss; mobj_t *mo = NULL; mapthing_t *mthing = NULL; @@ -7687,14 +7762,13 @@ void P_RespawnSpecials(void) mobjtype_t i; x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; + ss = R_PointInSubsector(x, y); // find which type to spawn for (i = 0; i < NUMMOBJTYPES; i++) if (mthing->type == mobjinfo[i].doomednum) break; - z = (mthing->options >> ZSHIFT) * FRACUNIT; - //CTF rings should continue to respawn as normal rings outside of CTF. if (gametype != GT_CTF) { @@ -7702,28 +7776,31 @@ void P_RespawnSpecials(void) i = MT_RING; } + if (mthing->options & MTF_OBJECTFLIP) + { + z = ss->sector->ceilingheight - (mthing->options >> ZSHIFT) * FRACUNIT; + if (mthing->options & MTF_AMBUSH + && (i == MT_RING || i == MT_REDTEAMRING || i == MT_BLUETEAMRING || i == MT_COIN || P_WeaponOrPanel(i))) + z -= 24*FRACUNIT; + z -= mobjinfo[i].height; // Don't forget the height! + } + else + { + z = ss->sector->floorheight + (mthing->options >> ZSHIFT) * FRACUNIT; + if (mthing->options & MTF_AMBUSH + && (i == MT_RING || i == MT_REDTEAMRING || i == MT_BLUETEAMRING || i == MT_COIN || P_WeaponOrPanel(i))) + z += 24*FRACUNIT; + } + mo = P_SpawnMobj(x, y, z, i); mo->spawnpoint = mthing; mo->angle = ANGLE_45 * (mthing->angle/45); if (mthing->options & MTF_OBJECTFLIP) { - mo->z = mo->ceilingz - (mthing->options >> ZSHIFT) * FRACUNIT; - if (mthing->options & MTF_AMBUSH - && (i == MT_RING || i == MT_REDTEAMRING || i == MT_BLUETEAMRING || i == MT_COIN || P_WeaponOrPanel(i))) - mo->z -= 24*FRACUNIT; - mo->z -= mobjinfo[i].height; // Don't forget the height! - mo->eflags |= MFE_VERTICALFLIP; mo->flags2 |= MF2_OBJECTFLIP; } - else - { - mo->z = mo->floorz + (mthing->options >> ZSHIFT) * FRACUNIT; - if (mthing->options & MTF_AMBUSH - && (i == MT_RING || i == MT_REDTEAMRING || i == MT_BLUETEAMRING || i == MT_COIN || P_WeaponOrPanel(i))) - mo->z += 24*FRACUNIT; - } } // pull it from the que iquetail = (iquetail+1)&(ITEMQUESIZE-1); @@ -7744,7 +7821,14 @@ void P_SpawnPlayer(INT32 playernum) // spawn as spectator determination if (!G_GametypeHasSpectators()) - p->spectator = false; + { + // Special case for (NiGHTS) special stages! + // if stage has already started, force players to become spectators until the next stage + if (multiplayer && netgame && G_IsSpecialStage(gamemap) && useNightsSS && leveltime > 0) + p->spectator = true; + else + p->spectator = false; + } else if (netgame && p->jointime < 1) p->spectator = true; else if (multiplayer && !netgame) @@ -7892,7 +7976,7 @@ void P_MovePlayerToSpawn(INT32 playernum, mapthing_t *mthing) { // Flagging a player's ambush will make them start on the ceiling // Objectflip inverts - if (((mthing->options & MTF_AMBUSH) == MTF_AMBUSH) ^ ((mthing->options & MTF_OBJECTFLIP) == MTF_OBJECTFLIP)) + if (!!(mthing->options & MTF_AMBUSH) ^ !!(mthing->options & MTF_OBJECTFLIP)) { z = sector->ceilingheight - mobjinfo[MT_PLAYER].height; if (mthing->options >> ZSHIFT) @@ -7905,8 +7989,11 @@ void P_MovePlayerToSpawn(INT32 playernum, mapthing_t *mthing) z += ((mthing->options >> ZSHIFT) << FRACBITS); } - if (mthing->options & MTF_OBJECTFLIP) - mobj->flags2 |= MF2_OBJECTFLIP; // flip the player! + if (mthing->options & MTF_OBJECTFLIP) // flip the player! + { + mobj->eflags |= MFE_VERTICALFLIP; + mobj->flags2 |= MF2_OBJECTFLIP; + } } else z = sector->floorheight; @@ -8230,16 +8317,7 @@ void P_SpawnMapThing(mapthing_t *mthing) z = ONFLOORZ; else if (i == MT_SPECIALSPIKEBALL || P_WeaponOrPanel(i) || i == MT_EMERALDSPAWN || i == MT_EMMY) { - if (!(mthing->options & MTF_OBJECTFLIP)) - { - z = ss->sector->floorheight; - - if (mthing->options & MTF_AMBUSH) // Special flag for rings - z += 24*FRACUNIT; - if (mthing->options >> ZSHIFT) - z += (mthing->options >> ZSHIFT)*FRACUNIT; - } - else + if (mthing->options & MTF_OBJECTFLIP) { z = ss->sector->ceilingheight; @@ -8250,6 +8328,15 @@ void P_SpawnMapThing(mapthing_t *mthing) z -= mobjinfo[i].height; //Don't forget the height! } + else + { + z = ss->sector->floorheight; + + if (mthing->options & MTF_AMBUSH) // Special flag for rings + z += 24*FRACUNIT; + if (mthing->options >> ZSHIFT) + z += (mthing->options >> ZSHIFT)*FRACUNIT; + } if (z == ONFLOORZ) mthing->z = 0; @@ -8259,7 +8346,7 @@ void P_SpawnMapThing(mapthing_t *mthing) else { fixed_t offset = 0; - boolean flip = (((mobjinfo[i].flags & MF_SPAWNCEILING) == MF_SPAWNCEILING) ^ ((mthing->options & MTF_OBJECTFLIP) == MTF_OBJECTFLIP)); + boolean flip = (!!(mobjinfo[i].flags & MF_SPAWNCEILING) ^ !!(mthing->options & MTF_OBJECTFLIP)); // base positions if (flip) @@ -8326,7 +8413,7 @@ void P_SpawnMapThing(mapthing_t *mthing) if (mthing->angle) mobj->health = mthing->angle; else - mobj->health = FixedMul((ss->sector->ceilingheight-ss->sector->floorheight), 3*(FRACUNIT/4))>>FRACBITS; + mobj->health = FixedMul(ss->sector->ceilingheight-ss->sector->floorheight, 3*(FRACUNIT/4))>>FRACBITS; break; case MT_WATERDRIP: if (mthing->angle) @@ -8517,7 +8604,7 @@ ML_NOCLIMB : Direction not controllable if (mthing->options & MTF_OBJECTSPECIAL) // No egg trap for this boss mobj->flags2 |= MF2_BOSSNOTRAP; - z = R_PointInSubsector(x, y)->sector->floorheight + ((mthing->options >> (ZSHIFT)) << FRACBITS); + z = ss->sector->floorheight + ((mthing->options >> (ZSHIFT)) << FRACBITS); mthing->z = (INT16)(z>>FRACBITS); } @@ -8569,22 +8656,6 @@ ML_NOCLIMB : Direction not controllable // Subtract 1 here for the correct value. mobj->health = 1 << (tokenbits - 1); } -/* else if (i == MT_EGGMOBILE && mthing->options & MTF_AMBUSH) - { - mobj_t *spikemobj; - spikemobj = P_SpawnMobj(x, y, z, MT_SPIKEBALL); - P_SetTarget(&spikemobj->target, mobj); - spikemobj->angle = 0; - spikemobj = P_SpawnMobj(x, y, z, MT_SPIKEBALL); - P_SetTarget(&spikemobj->target, mobj); - spikemobj->angle = ANGLE_90; - spikemobj = P_SpawnMobj(x, y, z, MT_SPIKEBALL); - P_SetTarget(&spikemobj->target, mobj); - spikemobj->angle = ANGLE_180; - spikemobj = P_SpawnMobj(x, y, z, MT_SPIKEBALL); - P_SetTarget(&spikemobj->target, mobj); - spikemobj->angle = ANGLE_270; - }*/ else if (i == MT_CYBRAKDEMON && mthing->options & MTF_AMBUSH) { mobj_t *elecmobj; @@ -8778,13 +8849,16 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) { mobj_t *mobj = NULL; INT32 r, i; - fixed_t x, y, z, finalx, finaly, finalz, mthingx, mthingy, mthingz; + fixed_t x, y, z, finalx, finaly, finalz; + sector_t *sec; TVector v, *res; angle_t closestangle, fa; x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; + sec = R_PointInSubsector(x, y)->sector; + // NiGHTS hoop! if (mthing->type == 1705) { @@ -8792,25 +8866,22 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) mobj_t *hoopcenter; INT16 spewangle; - mthingx = mthing->x << FRACBITS; - mthingy = mthing->y << FRACBITS; + z = mthing->options << FRACBITS; - mthingz = mthing->options << FRACBITS; - - hoopcenter = P_SpawnMobj(mthingx, mthingy, mthingz, MT_HOOPCENTER); + hoopcenter = P_SpawnMobj(x, y, z, MT_HOOPCENTER); hoopcenter->spawnpoint = mthing; // Screw these damn hoops, I need this thinker. //hoopcenter->flags |= MF_NOTHINK; - mthingz += R_PointInSubsector(mthingx, mthingy)->sector->floorheight; + z += sec->floorheight; - hoopcenter->z = mthingz - hoopcenter->height/2; + hoopcenter->z = z - hoopcenter->height/2; P_UnsetThingPosition(hoopcenter); - hoopcenter->x = mthingx; - hoopcenter->y = mthingy; + hoopcenter->x = x; + hoopcenter->y = y; P_SetThingPosition(hoopcenter); // Scale 0-255 to 0-359 =( @@ -8841,9 +8912,9 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle)); M_Memcpy(&v, res, sizeof (v)); - finalx = mthingx + v[0]; - finaly = mthingy + v[1]; - finalz = mthingz + v[2]; + finalx = x + v[0]; + finaly = y + v[1]; + finalz = z + v[2]; mobj = P_SpawnMobj(finalx, finaly, finalz, MT_HOOP); @@ -8879,9 +8950,9 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle)); M_Memcpy(&v, res, sizeof (v)); - finalx = mthingx + v[0]; - finaly = mthingy + v[1]; - finalz = mthingz + v[2]; + finalx = x + v[0]; + finaly = y + v[1]; + finalz = z + v[2]; mobj = P_SpawnMobj(finalx, finaly, finalz, MT_HOOPCOLLIDE); mobj->z -= mobj->height/2; @@ -8906,9 +8977,9 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle)); M_Memcpy(&v, res, sizeof (v)); - finalx = mthingx + v[0]; - finaly = mthingy + v[1]; - finalz = mthingz + v[2]; + finalx = x + v[0]; + finaly = y + v[1]; + finalz = z + v[2]; mobj = P_SpawnMobj(finalx, finaly, finalz, MT_HOOPCOLLIDE); mobj->z -= mobj->height/2; @@ -8931,21 +9002,18 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) INT32 hoopsize; INT32 hoopplacement; - mthingx = mthing->x << FRACBITS; - mthingy = mthing->y << FRACBITS; - // Save our flags! - mthingz = (mthing->options>>ZSHIFT) << FRACBITS; + z = (mthing->options>>ZSHIFT) << FRACBITS; - hoopcenter = P_SpawnMobj(mthingx, mthingy, mthingz, MT_HOOPCENTER); + hoopcenter = P_SpawnMobj(x, y, z, MT_HOOPCENTER); hoopcenter->spawnpoint = mthing; - mthingz += R_PointInSubsector(mthingx, mthingy)->sector->floorheight; - hoopcenter->z = mthingz - hoopcenter->height/2; + z += sec->floorheight; + hoopcenter->z = z - hoopcenter->height/2; P_UnsetThingPosition(hoopcenter); - hoopcenter->x = mthingx; - hoopcenter->y = mthingy; + hoopcenter->x = x; + hoopcenter->y = y; P_SetThingPosition(hoopcenter); // Scale 0-255 to 0-359 =( @@ -8982,9 +9050,9 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle)); M_Memcpy(&v, res, sizeof (v)); - finalx = mthingx + v[0]; - finaly = mthingy + v[1]; - finalz = mthingz + v[2]; + finalx = x + v[0]; + finaly = y + v[1]; + finalz = z + v[2]; mobj = P_SpawnMobj(finalx, finaly, finalz, MT_HOOP); @@ -9031,9 +9099,9 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle)); M_Memcpy(&v, res, sizeof (v)); - finalx = mthingx + v[0]; - finaly = mthingy + v[1]; - finalz = mthingz + v[2]; + finalx = x + v[0]; + finaly = y + v[1]; + finalz = z + v[2]; mobj = P_SpawnMobj(finalx, finaly, finalz, MT_HOOPCOLLIDE); mobj->z -= mobj->height/2; @@ -9052,12 +9120,13 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) // Wing logo item. else if (mthing->type == mobjinfo[MT_NIGHTSWING].doomednum) { + z = sec->floorheight; if (mthing->options >> ZSHIFT) - mthing->z = (INT16)((R_PointInSubsector(x, y)->sector->floorheight + ((mthing->options >> ZSHIFT) << FRACBITS))>>FRACBITS); - else - mthing->z = (INT16)(R_PointInSubsector(mthing->x << FRACBITS, mthing->y << FRACBITS)->sector->floorheight>>FRACBITS); + z += ((mthing->options >> ZSHIFT) << FRACBITS); - mobj = P_SpawnMobj(mthing->x << FRACBITS, mthing->y << FRACBITS,mthing->z << FRACBITS, MT_NIGHTSWING); + mthing->z = (INT16)(z>>FRACBITS); + + mobj = P_SpawnMobj(x, y, z, MT_NIGHTSWING); mobj->spawnpoint = mthing; if (G_IsSpecialStage(gamemap) && useNightsSS) @@ -9076,7 +9145,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) mobjtype_t ringthing = MT_RING; // No rings in Ultimate! - if (ultimatemode && !(G_IsSpecialStage(gamemap) || (maptol & TOL_NIGHTS))) + if (ultimatemode && !(G_IsSpecialStage(gamemap) || maptol & TOL_NIGHTS)) return; // Which ringthing to use @@ -9101,30 +9170,30 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) } // Set proper height - if (mthing->options >> ZSHIFT) + if (mthing->options & MTF_OBJECTFLIP) { - if (!(mthing->options & MTF_OBJECTFLIP)) - mthing->z = (INT16)((R_PointInSubsector(mthing->x << FRACBITS, mthing->y << FRACBITS)->sector->floorheight + ((mthing->options >> ZSHIFT) << FRACBITS))>>FRACBITS); - else - mthing->z = (INT16)((R_PointInSubsector(mthing->x << FRACBITS, mthing->y << FRACBITS)->sector->ceilingheight - mobjinfo[ringthing].height - ((mthing->options >> ZSHIFT) << FRACBITS))>>FRACBITS); + z = sec->ceilingheight - mobjinfo[ringthing].height; + if (mthing->options >> ZSHIFT) + z -= ((mthing->options >> ZSHIFT) << FRACBITS); } else { - if (!(mthing->options & MTF_OBJECTFLIP)) - mthing->z = (INT16)(R_PointInSubsector(mthing->x << FRACBITS, mthing->y << FRACBITS)->sector->floorheight>>FRACBITS); - else - mthing->z = (INT16)((R_PointInSubsector(mthing->x << FRACBITS, mthing->y << FRACBITS)->sector->ceilingheight - mobjinfo[ringthing].height)>>FRACBITS); + z = sec->floorheight; + if (mthing->options >> ZSHIFT) + z += ((mthing->options >> ZSHIFT) << FRACBITS); } if (mthing->options & MTF_AMBUSH) // Special flag for rings { - if (!(mthing->options & MTF_OBJECTFLIP)) - mthing->z += 24; + if (mthing->options & MTF_OBJECTFLIP) + z -= 24*FRACUNIT; else - mthing->z -= 24; + z += 24*FRACUNIT; } - mobj = P_SpawnMobj(mthing->x << FRACBITS, mthing->y << FRACBITS,mthing->z << FRACBITS, ringthing); + mthing->z = (INT16)(z>>FRACBITS); + + mobj = P_SpawnMobj(x, y, z, ringthing); mobj->spawnpoint = mthing; if (mthing->options & MTF_OBJECTFLIP) @@ -9150,7 +9219,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) dist = 128*FRACUNIT; // No rings in Ultimate! - if (ultimatemode && !(G_IsSpecialStage(gamemap) || (maptol & TOL_NIGHTS))) + if (ultimatemode && !(G_IsSpecialStage(gamemap) || maptol & TOL_NIGHTS)) return; #ifdef BLUE_SPHERES @@ -9161,19 +9230,17 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) for (r = 1; r <= 5; r++) { - if (mthing->options >> ZSHIFT) + if (mthing->options & MTF_OBJECTFLIP) { - if (!(mthing->options & MTF_OBJECTFLIP)) - z = (R_PointInSubsector(mthing->x << FRACBITS, mthing->y << FRACBITS)->sector->floorheight + ((mthing->options >> ZSHIFT) << FRACBITS)) + dist*r; - else - z = (R_PointInSubsector(mthing->x << FRACBITS, mthing->y << FRACBITS)->sector->ceilingheight - mobjinfo[ringthing].height - ((mthing->options >> ZSHIFT) << FRACBITS)) - dist*r; + z = sec->ceilingheight - mobjinfo[ringthing].height - dist*r; + if (mthing->options >> ZSHIFT) + z -= ((mthing->options >> ZSHIFT) << FRACBITS); } else { - if (!(mthing->options & MTF_OBJECTFLIP)) - z = R_PointInSubsector(mthing->x << FRACBITS, mthing->y << FRACBITS)->sector->floorheight + dist*r; - else - z = R_PointInSubsector(mthing->x << FRACBITS, mthing->y << FRACBITS)->sector->ceilingheight - mobjinfo[ringthing].height - dist*r; + z = sec->floorheight + dist*r; + if (mthing->options >> ZSHIFT) + z += ((mthing->options >> ZSHIFT) << FRACBITS); } mobj = P_SpawnMobj(x, y, z, ringthing); @@ -9199,7 +9266,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) iterations = 10; // No rings in Ultimate! - if (ultimatemode && !(G_IsSpecialStage(gamemap) || (maptol & TOL_NIGHTS))) + if (ultimatemode && !(G_IsSpecialStage(gamemap) || maptol & TOL_NIGHTS)) return; #ifdef BLUE_SPHERES @@ -9215,19 +9282,17 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) x += FixedMul(64*FRACUNIT, FINECOSINE(angle)); y += FixedMul(64*FRACUNIT, FINESINE(angle)); - if (mthing->options >> ZSHIFT) + if (mthing->options & MTF_OBJECTFLIP) { - if (!(mthing->options & MTF_OBJECTFLIP)) - z = (R_PointInSubsector(mthing->x << FRACBITS, mthing->y << FRACBITS)->sector->floorheight + ((mthing->options >> ZSHIFT) << FRACBITS)) + 64*FRACUNIT*r; - else - z = (R_PointInSubsector(mthing->x << FRACBITS, mthing->y << FRACBITS)->sector->ceilingheight - mobjinfo[ringthing].height - ((mthing->options >> ZSHIFT) << FRACBITS)) - 64*FRACUNIT*r; + z = sec->ceilingheight - mobjinfo[ringthing].height - 64*FRACUNIT*r; + if (mthing->options >> ZSHIFT) + z -= ((mthing->options >> ZSHIFT) << FRACBITS); } else { - if (!(mthing->options & MTF_OBJECTFLIP)) - z = R_PointInSubsector(mthing->x << FRACBITS, mthing->y << FRACBITS)->sector->floorheight + 64*FRACUNIT*r; - else - z = R_PointInSubsector(mthing->x << FRACBITS, mthing->y << FRACBITS)->sector->ceilingheight - mobjinfo[ringthing].height - 64*FRACUNIT*r; + z = sec->floorheight + 64*FRACUNIT*r; + if (mthing->options >> ZSHIFT) + z += ((mthing->options >> ZSHIFT) << FRACBITS); } mobj = P_SpawnMobj(x, y, z, ringthing); @@ -9256,13 +9321,9 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) size = 192*FRACUNIT; } - mthingx = mthing->x << FRACBITS; - mthingy = mthing->y << FRACBITS; - + z = sec->floorheight; if (mthing->options >> ZSHIFT) - mthingz = (R_PointInSubsector(x, y)->sector->floorheight + ((mthing->options >> ZSHIFT) << FRACBITS)); - else - mthingz = R_PointInSubsector(mthingx, mthingy)->sector->floorheight; + z += ((mthing->options >> ZSHIFT) << FRACBITS); closestangle = FixedAngle(mthing->angle*FRACUNIT); @@ -9309,9 +9370,9 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle)); M_Memcpy(&v, res, sizeof (v)); - finalx = mthingx + v[0]; - finaly = mthingy + v[1]; - finalz = mthingz + v[2]; + finalx = x + v[0]; + finaly = y + v[1]; + finalz = z + v[2]; mobj = P_SpawnMobj(finalx, finaly, finalz, itemToSpawn); mobj->z -= mobj->height/2; @@ -9451,7 +9512,7 @@ mobj_t *P_SpawnAlteredDirectionMissile(mobj_t *source, mobjtype_t type, fixed_t S_StartSound(th, th->info->seesound); P_SetTarget(&th->target, source->target); // where it came from - an = R_PointToAngle2(x, y, x+source->momx*16, y+source->momy*16) + (ANG1*shiftingAngle); + an = R_PointToAngle2(0, 0, source->momx, source->momy) + (ANG1*shiftingAngle); th->angle = an; an >>= ANGLETOFINESHIFT; diff --git a/src/p_saveg.c b/src/p_saveg.c index 462e68afe..3392d1e24 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -120,14 +120,8 @@ static inline void P_NetArchivePlayers(void) flags = 0; - // ticcmd write - WRITESINT8(save_p, players[i].cmd.forwardmove); - WRITESINT8(save_p, players[i].cmd.sidemove); - WRITEINT16(save_p, players[i].cmd.angleturn); - WRITEINT16(save_p, players[i].cmd.aiming); - WRITEUINT16(save_p, players[i].cmd.buttons); + // no longer send ticcmds, player name, skin, or color - WRITESTRINGN(save_p, player_names[i], MAXPLAYERNAME); WRITEANGLE(save_p, players[i].aiming); WRITEANGLE(save_p, players[i].awayviewaiming); WRITEINT32(save_p, players[i].awayviewtics); @@ -148,8 +142,6 @@ static inline void P_NetArchivePlayers(void) WRITEUINT16(save_p, players[i].flashpal); WRITEUINT16(save_p, players[i].flashcount); - WRITEUINT8(save_p, players[i].skincolor); - WRITEINT32(save_p, players[i].skin); WRITEUINT32(save_p, players[i].score); WRITEINT32(save_p, players[i].dashspeed); WRITEINT32(save_p, players[i].dashtime); @@ -289,26 +281,22 @@ static inline void P_NetUnArchivePlayers(void) { INT32 i, j; UINT16 flags; - ticcmd_t tmptic; if (READUINT32(save_p) != ARCHIVEBLOCK_PLAYERS) I_Error("Bad $$$.sav at archive block Players"); for (i = 0; i < MAXPLAYERS; i++) { - memset(&players[i], 0, sizeof (player_t)); + // Do NOT memset player struct to 0 + // other areas may initialize data elsewhere + //memset(&players[i], 0, sizeof (player_t)); if (!playeringame[i]) continue; - memset(&tmptic, 0, sizeof(ticcmd_t)); - tmptic.forwardmove = READSINT8(save_p); - tmptic.sidemove = READSINT8(save_p); - tmptic.angleturn = READINT16(save_p); - tmptic.aiming = READINT16(save_p); - tmptic.buttons = READUINT16(save_p); - G_CopyTiccmd(&players[i].cmd, &tmptic, 1); + // NOTE: sending tics should (hopefully) no longer be necessary + // sending player names, skin and color should not be necessary at all! + // (that data is handled in the server config now) - READSTRINGN(save_p, player_names[i], MAXPLAYERNAME); players[i].aiming = READANGLE(save_p); players[i].awayviewaiming = READANGLE(save_p); players[i].awayviewtics = READINT32(save_p); @@ -329,8 +317,6 @@ static inline void P_NetUnArchivePlayers(void) players[i].flashpal = READUINT16(save_p); players[i].flashcount = READUINT16(save_p); - players[i].skincolor = READUINT8(save_p); - players[i].skin = READINT32(save_p); players[i].score = READUINT32(save_p); players[i].dashspeed = READINT32(save_p); // dashing speed players[i].dashtime = READINT32(save_p); // dashing speed diff --git a/src/p_setup.c b/src/p_setup.c index c5b6995e4..bd2b0a478 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -220,6 +220,10 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) mapheaderinfo[num]->menuflags = 0; // TODO grades support for delfile (pfft yeah right) P_DeleteGrades(num); + // an even further impossibility, delfile custom opts support + mapheaderinfo[num]->customopts = NULL; + mapheaderinfo[num]->numCustomOptions = 0; + DEH_WriteUndoline(va("# uload for map %d", i), NULL, UNDO_DONE); } @@ -678,6 +682,7 @@ static void P_LoadSectors(lumpnum_t lumpnum) ss->lines = NULL; ss->heightsec = -1; + ss->camsec = -1; ss->floorlightsec = -1; ss->ceilinglightsec = -1; ss->crumblestate = 0; @@ -2559,6 +2564,15 @@ noscript: } #endif + // oh god I hope this helps + // (addendum: apparently it does! + // none of this needs to be done because it's not the beginning of the map when + // a netgame save is being loaded, and could actively be harmful by messing with + // the client's view of the data.) + if (fromnetsave) + goto netgameskip; + // ========== + for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) { @@ -2694,6 +2708,10 @@ noscript: else if (gametype == GT_RACE && server && cv_usemapnumlaps.value) CV_StealthSetValue(&cv_numlaps, mapheaderinfo[gamemap - 1]->numlaps); + // =========== + // landing point for netgames. + netgameskip: + if (!dedicated) { if (players[displayplayer].mo && (server || addedtogame)) @@ -2769,7 +2787,6 @@ noscript: if (twodlevel) { - CV_SetValue(&cv_cam_dist, 320); CV_SetValue(&cv_analog2, false); CV_SetValue(&cv_analog, false); } diff --git a/src/p_spec.c b/src/p_spec.c index 11660d20b..c29e47fa2 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1536,6 +1536,337 @@ static void P_AddExecutorDelay(line_t *line, mobj_t *mobj) static sector_t *triplinecaller; +/** Used by P_LinedefExecute to check a trigger linedef's conditions + * The linedef executor specials in the trigger linedef's sector are run if all conditions are met. + * Return false cancels P_LinedefExecute, this happens if a condition is not met. + * + * \param triggerline Trigger linedef to check conditions for; should NEVER be NULL. + * \param actor Object initiating the action; should not be NULL. + * \param caller Sector in which the action was started. May be NULL. + * \sa P_ProcessLineSpecial, P_LinedefExecute + */ +boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller) +{ + sector_t *ctlsector; + fixed_t dist = P_AproxDistance(triggerline->dx, triggerline->dy)>>FRACBITS; + size_t i, linecnt, sectori; + INT16 specialtype = triggerline->special; + + ///////////////////////////////////////////////// + // Distance-checking/sector trigger conditions // + ///////////////////////////////////////////////// + + // Linetypes 303 and 304 require a specific + // number, or minimum or maximum, of rings. + if (specialtype == 303 || specialtype == 304) + { + fixed_t rings = 0; + + // With the passuse flag, count all player's + // rings. + if (triggerline->flags & ML_EFFECT4) + { + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator) + continue; + + if (!players[i].mo || players[i].mo->health < 1) + continue; + + rings += players[i].mo->health-1; + } + } + else + { + if (!(actor && actor->player)) + return false; // no player to count rings from here, sorry + + rings = actor->health-1; + } + + if (triggerline->flags & ML_NOCLIMB) + { + if (rings > dist) + return false; + } + else if (triggerline->flags & ML_BLOCKMONSTERS) + { + if (rings < dist) + return false; + } + else + { + if (rings != dist) + return false; + } + } + else if (specialtype >= 314 && specialtype <= 315) + { + msecnode_t *node; + mobj_t *mo; + INT32 numpush = 0; + INT32 numneeded = dist; + + if (!caller) + return false; // we need a calling sector to find pushables in, silly! + + // Count the pushables in this sector + node = caller->touching_thinglist; // things touching this sector + while (node) + { + mo = node->m_thing; + if (mo->flags & MF_PUSHABLE) + numpush++; + node = node->m_snext; + } + + if (triggerline->flags & ML_NOCLIMB) // Need at least or more + { + if (numpush < numneeded) + return false; + } + else if (triggerline->flags & ML_EFFECT4) // Need less than + { + if (numpush >= numneeded) + return false; + } + else // Need exact + { + if (numpush != numneeded) + return false; + } + } + else if (caller) + { + if (GETSECSPECIAL(caller->special, 2) == 6) + { + if (!(ALL7EMERALDS(emeralds))) + return false; + } + else if (GETSECSPECIAL(caller->special, 2) == 7) + { + UINT8 mare; + + if (!(maptol & TOL_NIGHTS)) + return false; + + mare = P_FindLowestMare(); + + if (triggerline->flags & ML_NOCLIMB) + { + if (!(mare <= dist)) + return false; + } + else if (triggerline->flags & ML_BLOCKMONSTERS) + { + if (!(mare >= dist)) + return false; + } + else + { + if (!(mare == dist)) + return false; + } + } + // If we were not triggered by a sector type especially for the purpose, + // a Linedef Executor linedef trigger is not handling sector triggers properly, return. + + else if ((!GETSECSPECIAL(caller->special, 2) || GETSECSPECIAL(caller->special, 2) > 7) && (specialtype > 320)) + { + CONS_Alert(CONS_WARNING, + M_GetText("Linedef executor trigger isn't handling sector triggers properly!\nspecialtype = %d, if you are not a dev, report this warning instance\nalong with the wad that caused it!\n"), + specialtype); + return false; + } + } + + ////////////////////////////////////// + // Miscellaneous trigger conditions // + ////////////////////////////////////// + + switch (specialtype) + { + case 305: // continuous + case 306: // each time + case 307: // once + if (!(actor && actor->player && actor->player->charability != dist/10)) + return false; + break; + case 309: // continuous + case 310: // each time + // Only red team members can activate this. + if (!(actor && actor->player && actor->player->ctfteam == 1)) + return false; + break; + case 311: // continuous + case 312: // each time + // Only blue team members can activate this. + if (!(actor && actor->player && actor->player->ctfteam == 2)) + return false; + break; + case 317: // continuous + case 318: // once + { // Unlockable triggers required + INT32 trigid = (INT32)(sides[triggerline->sidenum[0]].textureoffset>>FRACBITS); + + if ((modifiedgame && !savemoddata) || (netgame || multiplayer)) + return false; + else if (trigid < 0 || trigid > 31) // limited by 32 bit variable + { + CONS_Debug(DBG_GAMELOGIC, "Unlockable trigger (sidedef %hu): bad trigger ID %d\n", triggerline->sidenum[0], trigid); + return false; + } + else if (!(unlocktriggers & (1 << trigid))) + return false; + } + break; + case 319: // continuous + case 320: // once + { // An unlockable itself must be unlocked! + INT32 unlockid = (INT32)(sides[triggerline->sidenum[0]].textureoffset>>FRACBITS); + + if ((modifiedgame && !savemoddata) || (netgame || multiplayer)) + return false; + else if (unlockid < 0 || unlockid >= MAXUNLOCKABLES) // limited by unlockable count + { + CONS_Debug(DBG_GAMELOGIC, "Unlockable check (sidedef %hu): bad unlockable ID %d\n", triggerline->sidenum[0], unlockid); + return false; + } + else if (!(unlockables[unlockid-1].unlocked)) + return false; + } + break; + default: + break; + } + + ///////////////////////////////// + // Processing linedef specials // + ///////////////////////////////// + + triplinecaller = caller; + ctlsector = triggerline->frontsector; + sectori = (size_t)(ctlsector - sectors); + linecnt = ctlsector->linecount; + + if (triggerline->flags & ML_EFFECT5) // disregard order for efficiency + { + for (i = 0; i < linecnt; i++) + if (ctlsector->lines[i]->special >= 400 + && ctlsector->lines[i]->special < 500) + { + if (ctlsector->lines[i]->flags & ML_DONTPEGTOP) + P_AddExecutorDelay(ctlsector->lines[i], actor); + else + P_ProcessLineSpecial(ctlsector->lines[i], actor); + } + } + else // walk around the sector in a defined order + { + boolean backwards = false; + size_t j, masterlineindex = (size_t)-1; + + for (i = 0; i < linecnt; i++) + if (ctlsector->lines[i] == triggerline) + { + masterlineindex = i; + break; + } + +#ifdef PARANOIA + if (masterlineindex == (size_t)-1) + { + const size_t li = (size_t)(ctlsector->lines[i] - lines); + I_Error("Line %s isn't linked into its front sector", sizeu1(li)); + } +#endif + + // i == masterlineindex + for (;;) + { + if (backwards) // v2 to v1 + { + for (j = 0; j < linecnt; j++) + { + if (i == j) + continue; + if (ctlsector->lines[i]->v1 == ctlsector->lines[j]->v2) + { + i = j; + break; + } + if (ctlsector->lines[i]->v1 == ctlsector->lines[j]->v1) + { + i = j; + backwards = false; + break; + } + } + if (j == linecnt) + { + const size_t vertexei = (size_t)(ctlsector->lines[i]->v1 - vertexes); + CONS_Debug(DBG_GAMELOGIC, "Warning: Sector %s is not closed at vertex %s (%d, %d)\n", + sizeu1(sectori), sizeu2(vertexei), ctlsector->lines[i]->v1->x, ctlsector->lines[i]->v1->y); + return false; // abort + } + } + else // v1 to v2 + { + for (j = 0; j < linecnt; j++) + { + if (i == j) + continue; + if (ctlsector->lines[i]->v2 == ctlsector->lines[j]->v1) + { + i = j; + break; + } + if (ctlsector->lines[i]->v2 == ctlsector->lines[j]->v2) + { + i = j; + backwards = true; + break; + } + } + if (j == linecnt) + { + const size_t vertexei = (size_t)(ctlsector->lines[i]->v1 - vertexes); + CONS_Debug(DBG_GAMELOGIC, "Warning: Sector %s is not closed at vertex %s (%d, %d)\n", + sizeu1(sectori), sizeu2(vertexei), ctlsector->lines[i]->v2->x, ctlsector->lines[i]->v2->y); + return false; // abort + } + } + + if (i == masterlineindex) + break; + + if (ctlsector->lines[i]->special >= 400 + && ctlsector->lines[i]->special < 500) + { + if (ctlsector->lines[i]->flags & ML_DONTPEGTOP) + P_AddExecutorDelay(ctlsector->lines[i], actor); + else + P_ProcessLineSpecial(ctlsector->lines[i], actor); + } + } + } + + // Special type 308, 307, 302, 304, 315, 318, and 320 only work once + if (specialtype == 302 || specialtype == 304 || specialtype == 307 || specialtype == 308 || specialtype == 315 || specialtype == 318 || specialtype == 320) + { + triggerline->special = 0; // Clear it out + + // Hmm, I'm thinking that we shouldn't touch the sector special, incase + // we have continuous executors associated with it, too? + /* + if (caller && (GETSECSPECIAL(caller->special, 2) >= 1 && GETSECSPECIAL(caller->special, 2) <= 7)) + caller->special = (UINT16)(caller->special-(GETSECSPECIAL(caller->special, 2) << 4)); // Only remove the relevant section + */ + } + return true; +} + /** Runs a linedef executor. * Can be called by: * - a player moving into a special sector or FOF. @@ -1546,15 +1877,12 @@ static sector_t *triplinecaller; * \param tag Tag of the linedef executor to run. * \param actor Object initiating the action; should not be NULL. * \param caller Sector in which the action was started. May be NULL. - * \sa P_ProcessLineSpecial + * \sa P_ProcessLineSpecial, P_RunTriggerLinedef * \author Graue */ void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller) { - sector_t *ctlsector; - fixed_t dist; - size_t masterline, i, linecnt, sectori; - INT16 specialtype; + size_t masterline; CONS_Debug(DBG_GAMELOGIC, "P_LinedefExecute: Executing trigger linedefs of tag %d\n", tag); @@ -1578,289 +1906,8 @@ void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller) || lines[masterline].special > 399) continue; - specialtype = lines[masterline].special; - - // Special handling for some executors - - // Linetypes 303 and 304 require a specific - // number, or minimum or maximum, of rings. - if (actor && actor->player && (specialtype == 303 - || specialtype == 304)) - { - fixed_t rings = 0; - - // With the passuse flag, count all player's - // rings. - if (lines[masterline].flags & ML_EFFECT4) - { - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i] || players[i].spectator) - continue; - - if (!players[i].mo || players[i].mo->health < 1) - continue; - - rings += players[i].mo->health-1; - } - } - else - rings = actor->health-1; - - dist = P_AproxDistance(lines[masterline].dx, lines[masterline].dy)>>FRACBITS; - - if (lines[masterline].flags & ML_NOCLIMB) - { - if (rings > dist) - return; - } - else if (lines[masterline].flags & ML_BLOCKMONSTERS) - { - if (rings < dist) - return; - } - else - { - if (rings != dist) - return; - } - } - else if (caller) - { - if (GETSECSPECIAL(caller->special, 2) == 6) - { - if (!(ALL7EMERALDS(emeralds))) - return; - } - else if (GETSECSPECIAL(caller->special, 2) == 7) - { - UINT8 mare; - - if (!(maptol & TOL_NIGHTS)) - return; - - dist = P_AproxDistance(lines[masterline].dx, lines[masterline].dy)>>FRACBITS; - mare = P_FindLowestMare(); - - if (lines[masterline].flags & ML_NOCLIMB) - { - if (!(mare <= dist)) - return; - } - else if (lines[masterline].flags & ML_BLOCKMONSTERS) - { - if (!(mare >= dist)) - return; - } - else - { - if (!(mare == dist)) - return; - } - } - // If we were not triggered by a sector type especially for the purpose, - // a Linedef Executor linedef trigger is not handling sector triggers properly, return. - - else if ((!GETSECSPECIAL(caller->special, 2) || GETSECSPECIAL(caller->special, 2) > 7) && (specialtype > 318)) - { - CONS_Alert(CONS_WARNING, - M_GetText("Linedef executor trigger isn't handling sector triggers properly!\nspecialtype = %d, if you are not a dev, report this warning instance\nalong with the wad that caused it!\n"), - specialtype); - } - - - if (specialtype >= 314 && specialtype <= 315) - { - msecnode_t *node; - mobj_t *mo; - INT32 numpush = 0; - INT32 numneeded = P_AproxDistance(lines[masterline].dx, lines[masterline].dy)>>FRACBITS; - - // Count the pushables in this sector - node = caller->touching_thinglist; // things touching this sector - while (node) - { - mo = node->m_thing; - if (mo->flags & MF_PUSHABLE) - numpush++; - node = node->m_snext; - } - - if (lines[masterline].flags & ML_NOCLIMB) // Need at least or more - { - if (numpush < numneeded) - return; - } - else if (lines[masterline].flags & ML_EFFECT4) // Need less than - { - if (numpush >= numneeded) - return; - } - else // Need exact - { - if (numpush != numneeded) - return; - } - } - } - - if (specialtype >= 305 && specialtype <= 307) - { - if (!actor) - return; - - if (!actor->player) - return; - - if (actor->player->charability != (P_AproxDistance(lines[masterline].dx, lines[masterline].dy)>>FRACBITS)/10) - return; - } - - // Only red team members can activate this. - if ((specialtype == 309 || specialtype == 310) - && !(actor && actor->player && actor->player->ctfteam == 1)) - return; - - // Only blue team members can activate this. - if ((specialtype == 311 || specialtype == 312) - && !(actor && actor->player && actor->player->ctfteam == 2)) - return; - - // Unlockable triggers required - if (specialtype <= 318 && specialtype >= 317) - { - INT32 trigid = (INT32)(sides[lines[masterline].sidenum[0]].textureoffset>>FRACBITS); - - if ((modifiedgame && !savemoddata) || (netgame || multiplayer)) - return; - else if (trigid < 0 || trigid > 31) // limited by 32 bit variable - { - CONS_Debug(DBG_GAMELOGIC, "Unlockable trigger (sidedef %hu): bad trigger ID %d\n", lines[masterline].sidenum[0], trigid); - return; - } - else if (!(unlocktriggers & (1 << trigid))) - return; - } - - triplinecaller = caller; - ctlsector = lines[masterline].frontsector; - sectori = (size_t)(ctlsector - sectors); - linecnt = ctlsector->linecount; - - if (lines[masterline].flags & ML_EFFECT5) // disregard order for efficiency - { - for (i = 0; i < linecnt; i++) - if (ctlsector->lines[i]->special >= 400 - && ctlsector->lines[i]->special < 500) - { - if (ctlsector->lines[i]->flags & ML_DONTPEGTOP) - P_AddExecutorDelay(ctlsector->lines[i], actor); - else - P_ProcessLineSpecial(ctlsector->lines[i], actor); - } - } - else // walk around the sector in a defined order - { - boolean backwards = false; - size_t j, masterlineindex = (size_t)-1; - - for (i = 0; i < linecnt; i++) - if (ctlsector->lines[i] == &lines[masterline]) - { - masterlineindex = i; - break; - } - -#ifdef PARANOIA - if (masterlineindex == (size_t)-1) - { - const size_t li = (size_t)(ctlsector->lines[i] - lines); - I_Error("Line %s isn't linked into its front sector", sizeu1(li)); - } -#endif - - // i == masterlineindex - for (;;) - { - if (backwards) // v2 to v1 - { - for (j = 0; j < linecnt; j++) - { - if (i == j) - continue; - if (ctlsector->lines[i]->v1 == ctlsector->lines[j]->v2) - { - i = j; - break; - } - if (ctlsector->lines[i]->v1 == ctlsector->lines[j]->v1) - { - i = j; - backwards = false; - break; - } - } - if (j == linecnt) - { - const size_t vertexei = (size_t)(ctlsector->lines[i]->v1 - vertexes); - CONS_Debug(DBG_GAMELOGIC, "Warning: Sector %s is not closed at vertex %s (%d, %d)\n", - sizeu1(sectori), sizeu2(vertexei), ctlsector->lines[i]->v1->x, ctlsector->lines[i]->v1->y); - return; // abort - } - } - else // v1 to v2 - { - for (j = 0; j < linecnt; j++) - { - if (i == j) - continue; - if (ctlsector->lines[i]->v2 == ctlsector->lines[j]->v1) - { - i = j; - break; - } - if (ctlsector->lines[i]->v2 == ctlsector->lines[j]->v2) - { - i = j; - backwards = true; - break; - } - } - if (j == linecnt) - { - const size_t vertexei = (size_t)(ctlsector->lines[i]->v1 - vertexes); - CONS_Debug(DBG_GAMELOGIC, "Warning: Sector %s is not closed at vertex %s (%d, %d)\n", - sizeu1(sectori), sizeu2(vertexei), ctlsector->lines[i]->v2->x, ctlsector->lines[i]->v2->y); - return; // abort - } - } - - if (i == masterlineindex) - break; - - if (ctlsector->lines[i]->special >= 400 - && ctlsector->lines[i]->special < 500) - { - if (ctlsector->lines[i]->flags & ML_DONTPEGTOP) - P_AddExecutorDelay(ctlsector->lines[i], actor); - else - P_ProcessLineSpecial(ctlsector->lines[i], actor); - } - } - } - - // Special type 308, 307, 302, 304, 315, and 318 only work once - if (specialtype == 302 || specialtype == 304 || specialtype == 307 || specialtype == 308 || specialtype == 315 || specialtype == 318) - { - lines[masterline].special = 0; // Clear it out - - // Hmm, I'm thinking that we shouldn't touch the sector special, incase - // we have continuous executors associated with it, too? - /* - if (caller && (GETSECSPECIAL(caller->special, 2) >= 1 && GETSECSPECIAL(caller->special, 2) <= 7)) - caller->special = (UINT16)(caller->special-(GETSECSPECIAL(caller->special, 2) << 4)); // Only remove the relevant section - */ - } + if (!P_RunTriggerLinedef(&lines[masterline], actor, caller)) + return; // cancel P_LinedefExecute if function returns false } } @@ -2201,21 +2248,15 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo) break;*/ case 409: // Change tagged sectors' tag - // (formerly "Change calling sectors' tag", but behavior - // was changed) + // (formerly "Change calling sectors' tag", but behavior was changed) { - while ((secnum = P_FindSectorFromLineTag(line, - secnum)) != -1) - { - P_ChangeSectorTag(secnum, - (INT16)(P_AproxDistance(line->dx, line->dy) - >>FRACBITS)); - } + while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0) + P_ChangeSectorTag(secnum,(INT16)(sides[line->sidenum[0]].textureoffset>>FRACBITS)); break; } case 410: // Change front sector's tag - P_ChangeSectorTag((UINT32)(line->frontsector - sectors), (INT16)(P_AproxDistance(line->dx, line->dy)>>FRACBITS)); + P_ChangeSectorTag((UINT32)(line->frontsector - sectors), (INT16)(sides[line->sidenum[0]].textureoffset>>FRACBITS)); break; case 411: // Stop floor/ceiling movement in tagged sector(s) @@ -3388,14 +3429,14 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers P_DoPlayerPain(player, NULL, NULL); // this does basically everything that was here before - if (gametype == GT_CTF && (player->gotflag & GF_REDFLAG || player->gotflag & GF_BLUEFLAG)) + if (gametype == GT_CTF && player->gotflag & (GF_REDFLAG|GF_BLUEFLAG)) P_PlayerFlagBurst(player, false); break; case 12: // Space Countdown if ((player->powers[pw_shield] & SH_NOSTACK) != SH_ELEMENTAL && !player->powers[pw_spacetime]) player->powers[pw_spacetime] = spacetimetics + 1; break; - case 13: // Ramp Sector (Increase step-up) + case 13: // Ramp Sector (Increase step-up/down) case 14: // Non-Ramp Sector (Don't step-down) case 15: // Bouncy Sector (FOF Control Only) break; @@ -4056,8 +4097,7 @@ DoneSection2: junk.dx = v2.x - v1.x; junk.dy = v2.y - v1.y; - P_ClosestPointOnLine(player->mo->x, player->mo->y, &junk, &resultlow); - resultlow.z = waypointmid->z; + P_ClosestPointOnLine3D(player->mo->x, player->mo->y, player->mo->z, &junk, &resultlow); } // Waypointmid and Waypointhigh: @@ -4074,11 +4114,10 @@ DoneSection2: junk.dx = v2.x - v1.x; junk.dy = v2.y - v1.y; - P_ClosestPointOnLine(player->mo->x, player->mo->y, &junk, &resulthigh); - resulthigh.z = waypointhigh->z; + P_ClosestPointOnLine3D(player->mo->x, player->mo->y, player->mo->z, &junk, &resulthigh); } - // 3D support not available yet. Need a 3D version of P_ClosestPointOnLine. + // 3D support now available. Disregard the previous notice here. -Red P_UnsetThingPosition(player->mo); P_ResetPlayer(player); @@ -4086,23 +4125,24 @@ DoneSection2: if (lines[lineindex].flags & ML_EFFECT1) // Don't wrap { - if (waypointhigh) - { - closest = waypointhigh; - player->mo->x = resulthigh.x; - player->mo->y = resulthigh.y; - player->mo->z = resulthigh.z - P_GetPlayerHeight(player); - } - else if (waypointlow) - { - closest = waypointmid; - player->mo->x = resultlow.x; - player->mo->y = resultlow.y; - player->mo->z = resultlow.z - P_GetPlayerHeight(player); - } - highest->flags |= MF_SLIDEME; } + + // Changing the conditions on these ifs to fix issues with snapping to the wrong spot -Red + if ((lines[lineindex].flags & ML_EFFECT1) && waypointmid->health == 0) + { + closest = waypointhigh; + player->mo->x = resulthigh.x; + player->mo->y = resulthigh.y; + player->mo->z = resulthigh.z - P_GetPlayerHeight(player); + } + else if ((lines[lineindex].flags & ML_EFFECT1) && waypointmid->health == highest->health) + { + closest = waypointmid; + player->mo->x = resultlow.x; + player->mo->y = resultlow.y; + player->mo->z = resultlow.z - P_GetPlayerHeight(player); + } else { if (P_AproxDistance(P_AproxDistance(player->mo->x-resultlow.x, player->mo->y-resultlow.y), @@ -5528,6 +5568,9 @@ void P_SpawnSpecials(INT32 fromnetsave) if (lines[i].flags & ML_EFFECT3) sectors[s].flags |= SF_TRIGGERSPECIAL_TOUCH; + + if (lines[i].frontsector && GETSECSPECIAL(lines[i].frontsector->special, 4) == 12) + sectors[s].camsec = sides[*lines[i].sidenum].sector-sectors; } break; @@ -6175,6 +6218,9 @@ void P_SpawnSpecials(INT32 fromnetsave) case 317: case 318: break; + case 319: + case 320: + break; case 399: // Linedef execute on map load // This is handled in P_RunLevelLoadExecutors. @@ -6588,7 +6634,7 @@ void T_Scroll(scroll_t *s) continue; if (!((thing = node->m_thing)->flags & MF_NOCLIP) && - (!(thing->flags & MF_NOGRAVITY || thing->z < height))) + (!(thing->flags & MF_NOGRAVITY || thing->z+thing->height < height))) { // Move objects only if on floor or underwater, // non-floating, and clipped. diff --git a/src/p_spec.h b/src/p_spec.h index 067c47f7a..04152f68d 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -60,6 +60,7 @@ boolean P_IsFlagAtBase(mobjtype_t flag); void P_SwitchWeather(INT32 weathernum); +boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller); void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller); void P_ChangeSectorTag(UINT32 sector, INT16 newtag); diff --git a/src/p_user.c b/src/p_user.c index 8549d51d5..5c8f2d91f 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -37,6 +37,7 @@ // We need to affect the NiGHTS hud #include "st_stuff.h" #include "lua_script.h" +#include "lua_hook.h" #include "b_bot.h" // Objectplace #include "m_cheat.h" @@ -597,21 +598,6 @@ static void P_DeNightserizePlayer(player_t *player) player->mo->flags2 &= ~MF2_DONTDRAW; - if (splitscreen && player == &players[secondarydisplayplayer]) - { - if (cv_analog2.value) - CV_SetValue(&cv_cam2_dist, 192); - else - CV_SetValue(&cv_cam2_dist, atoi(cv_cam2_dist.defaultvalue)); - } - else if (player == &players[displayplayer]) - { - if (cv_analog.value) - CV_SetValue(&cv_cam_dist, 192); - else - CV_SetValue(&cv_cam_dist, atoi(cv_cam_dist.defaultvalue)); - } - // Restore aiming angle if (player == &players[consoleplayer]) localaiming = 0; @@ -668,6 +654,14 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) if (player->bot) return; + if (!(player->pflags & PF_NIGHTSMODE)) + { + P_SetTarget(&player->mo->tracer, P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_NIGHTSCHAR)); + player->mo->tracer->destscale = player->mo->scale; + P_SetScale(player->mo->tracer, player->mo->scale); + player->mo->tracer->eflags = (player->mo->tracer->eflags & ~MFE_VERTICALFLIP)|(player->mo->eflags & MFE_VERTICALFLIP); + } + player->pflags &= ~(PF_USEDOWN|PF_JUMPDOWN|PF_ATTACKDOWN|PF_STARTDASH|PF_GLIDING|PF_JUMPED|PF_THOKKED|PF_SPINNING|PF_DRILLING); player->homing = 0; player->mo->fuse = 0; @@ -681,11 +675,6 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) player->mo->flags2 |= MF2_DONTDRAW; - if (splitscreen && player == &players[secondarydisplayplayer]) - CV_SetValue(&cv_cam2_dist, 320); - else if (player == &players[displayplayer]) - CV_SetValue(&cv_cam_dist, 320); - player->nightstime = player->startedtime = nighttime*TICRATE; player->bonustime = false; @@ -853,7 +842,7 @@ void P_DoPlayerPain(player_t *player, mobj_t *source, mobj_t *inflictor) } else { - ang = R_PointToAngle2(player->mo->x + player->mo->momx, player->mo->y + player->mo->momy, player->mo->x, player->mo->y); + ang = R_PointToAngle2(player->mo->momx, player->mo->momy, 0, 0); fallbackspeed = FixedMul(4*FRACUNIT, player->mo->scale); } @@ -1149,6 +1138,23 @@ void P_RestoreMusic(player_t *player) S_ChangeMusic(mapmusic, true); } +// +// P_IsObjectInGoop +// +// Returns true if the object is inside goop water. +// (Spectators and objects otherwise without gravity cannot have goop gravity!) +// +boolean P_IsObjectInGoop(mobj_t *mo) +{ + if (mo->player && mo->player->spectator) + return false; + + if (mo->flags & MF_NOGRAVITY) + return false; + + return ((mo->eflags & (MFE_UNDERWATER|MFE_GOOWATER)) == (MFE_UNDERWATER|MFE_GOOWATER)); +} + // // P_IsObjectOnGround // @@ -1158,8 +1164,9 @@ void P_RestoreMusic(player_t *player) // boolean P_IsObjectOnGround(mobj_t *mo) { - if ((mo->eflags & (MFE_UNDERWATER|MFE_GOOWATER)) == (MFE_UNDERWATER|MFE_GOOWATER) && !(mo->player && mo->player->spectator)) + if (P_IsObjectInGoop(mo)) { +/* // It's a crazy hack that checking if you're on the ground // would actually CHANGE your position and momentum, if (mo->z < mo->floorz) @@ -1172,6 +1179,7 @@ boolean P_IsObjectOnGround(mobj_t *mo) mo->z = mo->ceilingz - mo->height; mo->momz = 0; } +*/ // but I don't want you to ever 'stand' while submerged in goo. // You're in constant vertical momentum, even if you get stuck on something. // No exceptions. @@ -1404,7 +1412,7 @@ void P_SpawnShieldOrb(player_t *player) if (player->powers[pw_shield] & SH_FORCE) { //Copy and pasted from P_ShieldLook in p_mobj.c - shieldobj->movecount = (shieldobj->target->player->powers[pw_shield] & 0xFF); + shieldobj->movecount = (player->powers[pw_shield] & 0xFF); if (shieldobj->movecount < 1) { if (shieldobj->info->painstate) @@ -1586,8 +1594,13 @@ void P_DoPlayerExit(player_t *player) else player->exiting = (14*TICRATE)/5 + 2; // Accidental death safeguard??? - player->pflags &= ~PF_GLIDING; - player->climbing = 0; + //player->pflags &= ~PF_GLIDING; + if (player->climbing) + { + player->climbing = 0; + player->pflags |= PF_JUMPED; + P_SetPlayerMobjState(player->mo, S_PLAY_ATK1); + } player->powers[pw_underwater] = 0; player->powers[pw_spacetime] = 0; P_RestoreMusic(player); @@ -1597,7 +1610,7 @@ void P_DoPlayerExit(player_t *player) } #define SPACESPECIAL 12 -static boolean P_InSpaceSector(mobj_t *mo) // Returns true if you are in space +boolean P_InSpaceSector(mobj_t *mo) // Returns true if you are in space { sector_t *sector; @@ -1628,7 +1641,7 @@ static boolean P_InSpaceSector(mobj_t *mo) // Returns true if you are in space return false; // No vacuum here, Captain! } -static boolean P_InQuicksand(mobj_t *mo) // Returns true if you are in quicksand +boolean P_InQuicksand(mobj_t *mo) // Returns true if you are in quicksand { sector_t *sector; @@ -2061,46 +2074,39 @@ static void P_CheckUnderwaterAndSpaceTimer(player_t *player) // static void P_CheckInvincibilityTimer(player_t *player) { - ticcmd_t *cmd = &player->cmd; - if (mariomode && player->powers[pw_invulnerability] && !player->powers[pw_super]) - player->mo->color = (UINT8)(leveltime % MAXSKINCOLORS); - else + if (!player->powers[pw_invulnerability]) + return; + + if (mariomode && !player->powers[pw_super]) + player->mo->color = (UINT8)(1 + (leveltime % (MAXSKINCOLORS-1))); + else if (leveltime % (TICRATE/7) == 0) { - if (player->powers[pw_invulnerability] && leveltime % (TICRATE/7) == 0) + fixed_t destx, desty; + mobj_t *sparkle; + + if (!splitscreen && rendermode != render_soft) { - fixed_t destx, desty; - mobj_t *sparkle; + angle_t viewingangle; - if (!splitscreen && rendermode != render_soft) - { - angle_t viewingangle; - - if (players[displayplayer].awayviewtics) - viewingangle = R_PointToAngle2(player->mo->x, player->mo->y, players[displayplayer].awayviewmobj->x, players[displayplayer].awayviewmobj->y); - else if (!camera.chase && players[displayplayer].mo) - viewingangle = R_PointToAngle2(player->mo->x, player->mo->y, players[displayplayer].mo->x, players[displayplayer].mo->y); - else - viewingangle = R_PointToAngle2(player->mo->x, player->mo->y, camera.x, camera.y); - - destx = player->mo->x + P_ReturnThrustX(player->mo, viewingangle, FixedMul(FRACUNIT, player->mo->scale)); - desty = player->mo->y + P_ReturnThrustY(player->mo, viewingangle, FixedMul(FRACUNIT, player->mo->scale)); - } + if (players[displayplayer].awayviewtics) + viewingangle = R_PointToAngle2(player->mo->x, player->mo->y, players[displayplayer].awayviewmobj->x, players[displayplayer].awayviewmobj->y); + else if (!camera.chase && players[displayplayer].mo) + viewingangle = R_PointToAngle2(player->mo->x, player->mo->y, players[displayplayer].mo->x, players[displayplayer].mo->y); else - { - destx = player->mo->x; - desty = player->mo->y; - } + viewingangle = R_PointToAngle2(player->mo->x, player->mo->y, camera.x, camera.y); - sparkle = P_SpawnMobj(destx, desty, player->mo->z, MT_IVSP); - sparkle->destscale = player->mo->scale; - P_SetScale(sparkle, player->mo->scale); + destx = player->mo->x + P_ReturnThrustX(player->mo, viewingangle, FixedMul(FRACUNIT, player->mo->scale)); + desty = player->mo->y + P_ReturnThrustY(player->mo, viewingangle, FixedMul(FRACUNIT, player->mo->scale)); } - - if ((player->powers[pw_super]) && (cmd->forwardmove != 0 || cmd->sidemove != 0) - && !(leveltime % TICRATE) && (player->mo->momx || player->mo->momy)) + else { - P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SUPERSPARK); + destx = player->mo->x; + desty = player->mo->y; } + + sparkle = P_SpawnMobj(destx, desty, player->mo->z, MT_IVSP); + sparkle->destscale = player->mo->scale; + P_SetScale(sparkle, player->mo->scale); } // Resume normal music stuff. @@ -2150,7 +2156,7 @@ static void P_DoBubbleBreath(player_t *player) else zh = player->mo->z + FixedDiv(player->mo->height,5*(FRACUNIT/4)); - if (!(player->mo->eflags & MFE_UNDERWATER) || ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) || player->spectator) + if (!(player->mo->eflags & MFE_UNDERWATER) || ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL && !(player->pflags & PF_NIGHTSMODE)) || player->spectator) return; if (!(P_Random() % 16)) @@ -2164,6 +2170,9 @@ static void P_DoBubbleBreath(player_t *player) P_SetScale(bubble, bubble->destscale); } + if (player->pflags & PF_NIGHTSMODE) // NiGHTS Super doesn't spawn flight bubbles + return; + // Tails stirs up the water while flying in it if (player->powers[pw_tailsfly] && (leveltime & 1) && player->charability != CA_SWIM) { @@ -2391,11 +2400,12 @@ static void P_DoClimbing(player_t *player) } } - if (rover->flags & FF_CRUMBLE && !(netgame && player->spectator)) - EV_StartCrumble(rover->master->frontsector, rover, (rover->flags & FF_FLOATBOB), player, rover->alpha, !(rover->flags & FF_NORETURN)); - if (floorclimb) + { + if (rover->flags & FF_CRUMBLE && !(netgame && player->spectator)) + EV_StartCrumble(rover->master->frontsector, rover, (rover->flags & FF_FLOATBOB), player, rover->alpha, !(rover->flags & FF_NORETURN)); break; + } } } @@ -3181,6 +3191,13 @@ firenormal: // static void P_DoSuperStuff(player_t *player) { + ticcmd_t *cmd = &player->cmd; + if (player->mo->state >= &states[S_PLAY_SUPERTRANS1] && player->mo->state <= &states[S_PLAY_SUPERTRANS9]) + return; // don't do anything right now, we're in the middle of transforming! + + if (player->pflags & PF_NIGHTSMODE) + return; // NiGHTS Super doesn't mix with normal super + // Does player have all emeralds? If so, flag the "Ready For Super!" if ((ALL7EMERALDS(emeralds) || ALL7EMERALDS(player->powers[pw_emeralds])) && player->health > 50) player->pflags |= PF_SUPERREADY; @@ -3237,10 +3254,15 @@ static void P_DoSuperStuff(player_t *player) player->mo->color = SKINCOLOR_SUPER1 + (leveltime/2) % 5; break; } + + if ((cmd->forwardmove != 0 || cmd->sidemove != 0 || player->pflags & (PF_CARRIED|PF_ROPEHANG|PF_ITEMHANG|PF_MACESPIN)) + && !(leveltime % TICRATE) && (player->mo->momx || player->mo->momy)) + P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SUPERSPARK); + G_GhostAddColor(GHC_SUPER); // Ran out of rings while super! - if (player->powers[pw_super] && (player->health <= 1 || player->exiting)) + if (player->health <= 1 || player->exiting) { player->powers[pw_emeralds] = 0; // lost the power stones P_SpawnGhostMobj(player->mo); @@ -3355,6 +3377,8 @@ void P_DoJump(player_t *player, boolean soundandstate) // Quicksand jumping. else if (P_InQuicksand(player->mo)) { + if (player->mo->ceilingz-player->mo->floorz <= player->mo->height-1) + return; player->mo->momz += (39*(FRACUNIT/4))>>1; if (player->mo->momz >= 6*FRACUNIT) player->mo->momz = 6*FRACUNIT; //max momz in quicksand @@ -3486,6 +3510,14 @@ static void P_DoSpinDash(player_t *player, ticcmd_t *cmd) if (player->pflags & PF_STASIS) return; +#ifdef HAVE_BLUA + if (cmd->buttons & BT_USE) + { + if (LUAh_SpinSpecial(player)) + return; + } +#endif + // Spinning and Spindashing if ((player->charability2 == CA2_SPINDASH) && !(player->pflags & PF_SLIDING) && !player->exiting && !P_PlayerInPain(player)) // subsequent revs @@ -3570,7 +3602,7 @@ static void P_DoSpinDash(player_t *player, ticcmd_t *cmd) // // Jump Shield Activation // -static void P_DoJumpShield(player_t *player) +void P_DoJumpShield(player_t *player) { if (player->pflags & PF_THOKKED) return; @@ -3652,10 +3684,13 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) { if (onground || player->climbing || player->pflags & (PF_CARRIED|PF_ITEMHANG|PF_ROPEHANG)) {} - else if ((player->pflags & PF_MACESPIN) && player->mo->tracer) + else if (player->pflags & PF_MACESPIN && player->mo->tracer) {} else if (!(player->pflags & PF_SLIDING) && ((gametype != GT_CTF) || (!player->gotflag))) { +#ifdef HAVE_BLUA + if (!LUAh_JumpSpinSpecial(player)) +#endif switch (player->charability) { case CA_TELEKINESIS: @@ -3705,8 +3740,16 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) } } - if (cmd->buttons & BT_JUMP && !(player->pflags & PF_JUMPDOWN) && !player->exiting && !P_PlayerInPain(player)) + if (cmd->buttons & BT_JUMP && !player->exiting && !P_PlayerInPain(player)) { +#ifdef HAVE_BLUA + if (LUAh_JumpSpecial(player)) + ; + else +#endif + if (player->pflags & PF_JUMPDOWN) // all situations below this require jump button not to be pressed already + ; + else // Jump S3&K style while in quicksand. if (P_InQuicksand(player->mo)) { @@ -3722,85 +3765,85 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) player->secondjump = 0; player->pflags &= ~PF_THOKKED; } - else if ((player->pflags & PF_MACESPIN) && player->mo->tracer) + else if (player->pflags & PF_MACESPIN && player->mo->tracer) { player->pflags &= ~PF_MACESPIN; player->powers[pw_flashing] = TICRATE/4; } - else if (!(player->pflags & PF_SLIDING) && ((gametype != GT_CTF) || (!player->gotflag))) + else if (player->pflags & PF_SLIDING || (gametype == GT_CTF && player->gotflag)) + ; + else if (P_SuperReady(player)) { + // If you can turn super and aren't already, + // and you don't have a shield, do it! + P_DoSuperTransformation(player, false); + } + else if (player->pflags & PF_JUMPED) + { +#ifdef HAVE_BLUA + if (!LUAh_AbilitySpecial(player)) +#endif switch (player->charability) { case CA_THOK: case CA_HOMINGTHOK: case CA_JUMPTHOK: // Credit goes to CZ64 and Sryder13 for the original // Now it's Sonic's abilities turn! - if (player->pflags & PF_JUMPED) + // THOK! + if (!(player->pflags & PF_THOKKED) || ((player->charability2 == CA2_MULTIABILITY) /*&& (!(player->charability == CA_JUMPTHOK))*/)) { - // If you can turn super and aren't already, - // and you don't have a shield, do it! - if (P_SuperReady(player)) - P_DoSuperTransformation(player, false); - else // Otherwise, THOK! + // Catapult the player + fixed_t actionspd = player->actionspd; + if (player->mo->eflags & MFE_UNDERWATER) + actionspd >>= 1; + if (player->charability == CA_JUMPTHOK) { - if (!(player->pflags & PF_THOKKED) || ((player->charability2 == CA2_MULTIABILITY) && (!(player->charability == CA_JUMPTHOK)))) + // Enforcing an arbitrary limit, even on just the default setting, is bad; it encourages bad WADmaking practice and disables use of that particular action speed. + // Instead, see the speed limit in 2D with the added condition below! I think that works much better, and is more consistent. -Red + //if ((actionspd == 60*FRACUNIT) && (actionspd > player->normalspeed)) //Limit only at default + //actionspd = player->normalspeed; + player->pflags &= ~PF_JUMPED; + P_DoJump(player, false); + } + P_InstaThrust(player->mo, player->mo->angle, FixedMul(actionspd, player->mo->scale)); + + if ((maptol & TOL_2D) || (player->charability == CA_JUMPTHOK)) + { + player->mo->momx /= 2; + player->mo->momy /= 2; + } + else if (player->charability == CA_HOMINGTHOK) + { + player->mo->momx /= 3; + player->mo->momy /= 3; + } + + if (player->mo->info->attacksound && !player->spectator) + S_StartSound(player->mo, player->mo->info->attacksound); // Play the THOK sound + + P_SpawnThokMobj(player); + + if (player->charability == CA_HOMINGTHOK && !player->homing) + { + if (P_LookForEnemies(player)) { - // Catapult the player - fixed_t actionspd = player->actionspd; - if (player->mo->eflags & MFE_UNDERWATER) - actionspd >>= 1; - if (player->charability == CA_JUMPTHOK) - { - if ((actionspd == 60*FRACUNIT) && (actionspd > player->normalspeed)) //Limit only at default - actionspd = player->normalspeed; - player->pflags &= ~PF_JUMPED; - P_DoJump(player, false); - } - P_InstaThrust(player->mo, player->mo->angle, FixedMul(actionspd, player->mo->scale)); - - if (maptol & TOL_2D) - { - player->mo->momx /= 2; - player->mo->momy /= 2; - } - else if (player->charability == CA_HOMINGTHOK) - { - player->mo->momx /= 3; - player->mo->momy /= 3; - } - - if (player->mo->info->attacksound && !player->spectator) - S_StartSound(player->mo, player->mo->info->attacksound); // Play the THOK sound - - P_SpawnThokMobj(player); - - if ((player->charability == CA_HOMINGTHOK) && !player->homing && (player->pflags & PF_JUMPED)) - { - if (P_LookForEnemies(player)) - { - if (player->mo->tracer) - player->homing = 3*TICRATE; - } - } - - player->pflags &= ~(PF_SPINNING|PF_STARTDASH); - player->pflags |= PF_THOKKED; + if (player->mo->tracer) + player->homing = 3*TICRATE; } } + + player->pflags &= ~(PF_SPINNING|PF_STARTDASH); + player->pflags |= PF_THOKKED; } - else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_JUMP && !player->powers[pw_super]) - P_DoJumpShield(player); break; case CA_FLY: case CA_SWIM: // Swim - // If you can turn super and aren't already, - // and you don't have a shield, do it! - if (P_SuperReady(player)) - P_DoSuperTransformation(player, false); // If currently in the air from a jump, and you pressed the // button again and have the ability to fly, do so! - else if (!(player->pflags & PF_THOKKED) && !(player->powers[pw_tailsfly]) && (player->pflags & PF_JUMPED) && !(player->charability == CA_SWIM && !(player->mo->eflags & MFE_UNDERWATER))) + if (player->charability == CA_SWIM && !(player->mo->eflags & MFE_UNDERWATER)) + ; // Can't do anything if you're a fish out of water! + else if (!(player->pflags & PF_THOKKED) && !(player->powers[pw_tailsfly])) { P_SetPlayerMobjState(player->mo, S_PLAY_ABL1); // Change to the flying animation @@ -3809,32 +3852,12 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) player->pflags &= ~(PF_JUMPED|PF_SPINNING|PF_STARTDASH); player->pflags |= PF_THOKKED; } - // If currently flying, give an ascend boost. - else if (player->powers[pw_tailsfly] && !(player->charability == CA_SWIM && !(player->mo->eflags & MFE_UNDERWATER))) - { - if (!player->fly1) - player->fly1 = 20; - else - player->fly1 = 2; - - if (player->charability == CA_SWIM) - player->fly1 /= 2; - - // Slow down! - if (player->speed > FixedMul(8*FRACUNIT, player->mo->scale) && player->speed > FixedMul(player->normalspeed>>1, player->mo->scale)) - P_Thrust(player->mo, R_PointToAngle2(0,0,player->mo->momx,player->mo->momy), FixedMul(-4*FRACUNIT, player->mo->scale)); - } - else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_JUMP && !player->powers[pw_super]) - P_DoJumpShield(player); break; - case CA_GLIDEANDCLIMB: // Now Knuckles-type abilities are checked. // If you can turn super and aren't already, // and you don't have a shield, do it! - if (P_SuperReady(player)) - P_DoSuperTransformation(player, false); - else if ((player->pflags & PF_JUMPED) && (!(player->pflags & PF_THOKKED) || player->charability2 == CA2_MULTIABILITY)) + if (!(player->pflags & PF_THOKKED) || player->charability2 == CA2_MULTIABILITY) { INT32 glidespeed = player->actionspd; @@ -3852,13 +3875,9 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) P_InstaThrust(player->mo, player->mo->angle, FixedMul(glidespeed, player->mo->scale)); player->pflags &= ~(PF_SPINNING|PF_STARTDASH); } - else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_JUMP && !player->powers[pw_super]) - P_DoJumpShield(player); break; case CA_DOUBLEJUMP: // Double-Jump - if (P_SuperReady(player)) - P_DoSuperTransformation(player, false); - else if ((player->pflags & PF_JUMPED) && !(player->pflags & PF_THOKKED)) + if (!(player->pflags & PF_THOKKED)) { player->pflags &= ~PF_JUMPED; P_DoJump(player, true); @@ -3867,81 +3886,100 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) if (!player->powers[pw_super]) player->pflags |= PF_THOKKED; } - else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_JUMP && !player->powers[pw_super]) - P_DoJumpShield(player); break; case CA_FLOAT: // Float case CA_SLOWFALL: // Slow descent hover - if (P_SuperReady(player)) - P_DoSuperTransformation(player, false); - else if ((player->pflags & PF_JUMPED) && !player->secondjump) + if (!player->secondjump) player->secondjump = 1; - else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_JUMP && !player->powers[pw_super]) - P_DoJumpShield(player); break; case CA_TELEKINESIS: - if (P_SuperReady(player)) - P_DoSuperTransformation(player, false); - else if (player->pflags & PF_JUMPED) + if (!(player->pflags & PF_THOKKED) || player->charability2 == CA2_MULTIABILITY) { - if (!(player->pflags & PF_THOKKED) || (player->charability2 == CA2_MULTIABILITY)) - { - P_Telekinesis(player, - FixedMul(player->actionspd, player->mo->scale), // +ve thrust (pushing away from player) - FixedMul(384*FRACUNIT, player->mo->scale)); - } + P_Telekinesis(player, + FixedMul(player->actionspd, player->mo->scale), // +ve thrust (pushing away from player) + FixedMul(384*FRACUNIT, player->mo->scale)); } - else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_JUMP && !player->powers[pw_super]) - P_DoJumpShield(player); break; case CA_FALLSWITCH: - if (P_SuperReady(player)) - P_DoSuperTransformation(player, false); - else if (player->pflags & PF_JUMPED) + if (!(player->pflags & PF_THOKKED) || player->charability2 == CA2_MULTIABILITY) { - if (!(player->pflags & PF_THOKKED) || (player->charability2 == CA2_MULTIABILITY)) - { - player->mo->momz = -player->mo->momz; - P_SpawnThokMobj(player); - player->pflags |= PF_THOKKED; - } + player->mo->momz = -player->mo->momz; + P_SpawnThokMobj(player); + player->pflags |= PF_THOKKED; } - else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_JUMP && !player->powers[pw_super]) - P_DoJumpShield(player); break; case CA_AIRDRILL: - if (P_SuperReady(player)) - P_DoSuperTransformation(player, false); - else if(player->pflags & PF_JUMPED) + if (!(player->pflags & PF_THOKKED) || player->charability2 == CA2_MULTIABILITY) { - if (!(player->pflags & PF_THOKKED) || (player->charability2 == CA2_MULTIABILITY)) - { - player->flyangle = 56 + (60-(player->actionspd>>FRACBITS))/3; - player->pflags |= PF_THOKKED; - S_StartSound(player->mo, sfx_spndsh); - } + player->flyangle = 56 + (60-(player->actionspd>>FRACBITS))/3; + player->pflags |= PF_THOKKED; + S_StartSound(player->mo, sfx_spndsh); } - else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_JUMP && !player->powers[pw_super]) - P_DoJumpShield(player); - break; - case CA_JUMPBOOST: - case CA_NONE: - // Characters who don't normally have a second jump of any sort - // There's still stuff for them to do of course! - if (P_SuperReady(player)) - P_DoSuperTransformation(player, false); - else if (!(player->pflags & PF_JUMPED) && (player->powers[pw_shield] & SH_NOSTACK) == SH_JUMP && !player->powers[pw_super]) - P_DoJumpShield(player); break; default: break; } } - } - player->pflags |= PF_JUMPDOWN; + else if (player->pflags & PF_THOKKED) + { +#ifdef HAVE_BLUA + if (!LUAh_AbilitySpecial(player)) +#endif + switch (player->charability) + { + case CA_FLY: + case CA_SWIM: // Swim + if (player->charability == CA_SWIM && !(player->mo->eflags & MFE_UNDERWATER)) + ; // Can't do anything if you're a fish out of water! + else if (player->powers[pw_tailsfly]) // If currently flying, give an ascend boost. + { + if (!player->fly1) + player->fly1 = 20; + else + player->fly1 = 2; - if (!(cmd->buttons & BT_JUMP))// If not pressing the jump button + if (player->charability == CA_SWIM) + player->fly1 /= 2; + + // Slow down! + if (player->speed > FixedMul(8*FRACUNIT, player->mo->scale) && player->speed > FixedMul(player->normalspeed>>1, player->mo->scale)) + P_Thrust(player->mo, R_PointToAngle2(0,0,player->mo->momx,player->mo->momy), FixedMul(-4*FRACUNIT, player->mo->scale)); + } + break; + default: + break; + } + } + else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_JUMP && !player->powers[pw_super]) + P_DoJumpShield(player); + } + + if (cmd->buttons & BT_JUMP) + { + player->pflags |= PF_JUMPDOWN; + + if ((gametype != GT_CTF || !player->gotflag) && !player->exiting) + { + if (player->secondjump == 1) + { + if (player->charability == CA_FLOAT) + player->mo->momz = 0; + else if (player->charability == CA_SLOWFALL) + { + if (player->powers[pw_super]) + { + if (P_MobjFlip(player->mo)*player->mo->momz < gravity*16) + player->mo->momz = P_MobjFlip(player->mo)*gravity*16; //Float upward 4x as fast while super. + } + else if (P_MobjFlip(player->mo)*player->mo->momz < -gravity*4) + player->mo->momz = P_MobjFlip(player->mo)*-gravity*4; + } + player->pflags &= ~PF_SPINNING; + } + } + } + else // If not pressing the jump button { player->pflags &= ~PF_JUMPDOWN; @@ -3949,44 +3987,25 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) if ((player->charability2 == CA2_MULTIABILITY && player->charability != CA_DOUBLEJUMP) || (player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds]))) player->secondjump = 0; - else if ((player->charability == CA_FLOAT) && player->secondjump == 1) + else if (player->charability == CA_FLOAT && player->secondjump == 1) player->secondjump = 2; - } - if ((gametype != GT_CTF) || (!player->gotflag)) - { - if (player->secondjump == 1 && (cmd->buttons & BT_JUMP)) + + // If letting go of the jump button while still on ascent, cut the jump height. + if (player->pflags & PF_JUMPED && P_MobjFlip(player->mo)*player->mo->momz > 0 && player->jumping == 1) { - if (player->charability == CA_FLOAT) - player->mo->momz = 0; - else if (player->charability == CA_SLOWFALL) - { - if (!(player->mo->eflags & MFE_VERTICALFLIP)) - { - if (!player->powers[pw_super] && player->mo->momz < -gravity*4) - player->mo->momz = -gravity*4; - else if (player->powers[pw_super] && player->mo->momz < gravity*16) - player->mo->momz = gravity*16; //Float upward 4x as fast while super. - } - else - { - if (!player->powers[pw_super] && player->mo->momz > gravity*4) - player->mo->momz = gravity*4; - else if (player->powers[pw_super] && player->mo->momz > -gravity*16) - player->mo->momz = -gravity*16; //Float "upward" 4x as fast while super. - } - } - - player->pflags &= ~PF_SPINNING; + player->mo->momz >>= 1; + player->jumping = 0; } } +} - // If letting go of the jump button while still on ascent, cut the jump height. - if (!(player->pflags & PF_JUMPDOWN) && (player->pflags & PF_JUMPED) && P_MobjFlip(player->mo)*player->mo->momz > 0 && player->jumping == 1) - { - player->mo->momz >>= 1; - player->jumping = 0; - } +static boolean P_AnalogMove(player_t *player) +{ + if (netgame) + return false; + return ((player == &players[consoleplayer] && cv_analog.value) + || (player == &players[secondarydisplayplayer] && cv_analog2.value)); } // @@ -4003,94 +4022,54 @@ INT32 P_GetPlayerControlDirection(player_t *player) ticcmd_t *cmd = &player->cmd; angle_t controllerdirection, controlplayerdirection; camera_t *thiscam; + angle_t dangle; + fixed_t tempx = 0, tempy = 0; + angle_t tempangle, origtempangle; if (splitscreen && player == &players[secondarydisplayplayer]) thiscam = &camera2; else thiscam = &camera; - if (!netgame && ((player == &players[consoleplayer] && cv_analog.value) - || (player == &players[secondarydisplayplayer] - && cv_analog2.value)) && thiscam->chase) + if (!cmd->forwardmove && !cmd->sidemove) + return 0; + + if (P_AnalogMove(player) && thiscam->chase) { - fixed_t tempx, tempy; - angle_t tempangle; - - tempx = tempy = 0; - - // Calculate the angle at which the controls are pointing - // to figure out the proper mforward and mbackward. - tempangle = thiscam->angle; - tempangle >>= ANGLETOFINESHIFT; - tempx += FixedMul(cmd->forwardmove,FINECOSINE(tempangle)); - tempy += FixedMul(cmd->forwardmove,FINESINE(tempangle)); - - tempangle = thiscam->angle-ANGLE_90; - tempangle >>= ANGLETOFINESHIFT; - tempx += FixedMul(cmd->sidemove,FINECOSINE(tempangle)); - tempy += FixedMul(cmd->sidemove,FINESINE(tempangle)); - - tempx = tempx*FRACUNIT; - tempy = tempy*FRACUNIT; - - controllerdirection = - R_PointToAngle2(player->mo->x, player->mo->y, player->mo->x + tempx, - player->mo->y + tempy); - + if (player->awayviewtics) + origtempangle = tempangle = player->awayviewmobj->angle; + else + origtempangle = tempangle = thiscam->angle; controlplayerdirection = player->mo->angle; - - if (controlplayerdirection < ANGLE_90) - { - controlplayerdirection += ANGLE_90; - controllerdirection += ANGLE_90; - } - else if (controlplayerdirection >= ANGLE_270) - { - controlplayerdirection -= ANGLE_90; - controllerdirection -= ANGLE_90; - } - - // Controls pointing backwards from player - if (controllerdirection > controlplayerdirection + ANGLE_90 - && controllerdirection < controlplayerdirection - ANGLE_90) - { - return 2; - } - else // Controls pointing in player's general direction - return 1; } else { - if (!cmd->forwardmove) - return 0; + origtempangle = tempangle = player->mo->angle; + controlplayerdirection = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); } - controllerdirection = - R_PointToAngle2(player->mo->x, player->mo->y, P_ReturnThrustX(player->mo, player->mo->angle, cmd->forwardmove), - P_ReturnThrustY(player->mo, player->mo->angle, cmd->forwardmove)); + // Calculate the angle at which the controls are pointing + // to figure out the proper mforward and mbackward. + tempangle >>= ANGLETOFINESHIFT; + tempx += FixedMul(cmd->forwardmove*FRACUNIT,FINECOSINE(tempangle)); + tempy += FixedMul(cmd->forwardmove*FRACUNIT,FINESINE(tempangle)); - controlplayerdirection = R_PointToAngle2(0, 0, player->mo->momx, - player->mo->momy); + tempangle = origtempangle-ANGLE_90; + tempangle >>= ANGLETOFINESHIFT; + tempx += FixedMul(cmd->sidemove*FRACUNIT,FINECOSINE(tempangle)); + tempy += FixedMul(cmd->sidemove*FRACUNIT,FINESINE(tempangle)); - if (controlplayerdirection < ANGLE_90) - { - controlplayerdirection += ANGLE_90; - controllerdirection += ANGLE_90; - } - else if (controlplayerdirection >= ANGLE_270) - { - controlplayerdirection -= ANGLE_90; - controllerdirection -= ANGLE_90; - } + controllerdirection = R_PointToAngle2(0, 0, tempx, tempy); - // Controls pointing backwards from player - if (controllerdirection > controlplayerdirection + ANGLE_90 - && controllerdirection < controlplayerdirection - ANGLE_90) - { - return 2; - } - else // Controls pointing in player's general direction - return 1; + dangle = controllerdirection - controlplayerdirection; + + if (dangle > ANGLE_180) //flip to keep to one side + dangle = InvAngle(dangle); + + if (dangle > ANGLE_90) + return 2; // Controls pointing backwards from player + else + return 1; // Controls pointing in player's general direction } // Control scheme for 2d levels. @@ -4239,8 +4218,7 @@ static void P_2dMovement(player_t *player) player->mo->momx = 0; } - - if (cmd->sidemove != 0 && !(player->climbing || player->pflags & PF_GLIDING || player->exiting + else if (cmd->sidemove != 0 && !(player->pflags & PF_GLIDING || player->exiting || (P_PlayerInPain(player) && !onground))) { movepushforward = abs(cmd->sidemove) * (thrustfactor * acceleration); @@ -4290,10 +4268,7 @@ static void P_3dMovement(player_t *player) else thiscam = &camera; - analogmove = (!netgame - && ((player == &players[consoleplayer] && cv_analog.value) - || (player == &players[secondarydisplayplayer] && cv_analog2.value)) - && thiscam->chase); + analogmove = (P_AnalogMove(player) && thiscam->chase); cmd = &player->cmd; @@ -4320,14 +4295,16 @@ static void P_3dMovement(player_t *player) if (analogmove) { - movepushangle = thiscam->angle; - movepushsideangle = thiscam->angle-ANGLE_90; + if (player->awayviewtics) + movepushangle = player->awayviewmobj->angle; + else + movepushangle = thiscam->angle; } else { movepushangle = player->mo->angle; - movepushsideangle = player->mo->angle-ANGLE_90; } + movepushsideangle = movepushangle-ANGLE_90; // cmomx/cmomy stands for the conveyor belt speed. if (player->onconveyor == 2) // Wind/Current @@ -4493,58 +4470,43 @@ static void P_3dMovement(player_t *player) { if (!(player->pflags & PF_GLIDING || player->exiting || P_PlayerInPain(player))) { - angle_t controldirection, controllerdirection, controlplayerdirection; - fixed_t tempx, tempy; + angle_t controldirection; + fixed_t tempx = 0, tempy = 0; angle_t tempangle; #ifdef OLD_MOVEMENT_CODE + angle_t controlplayerdirection; boolean cforward; // controls pointing forward from the player boolean cbackward; // controls pointing backward from the player -#endif + angle_t dangle; - tempx = tempy = 0; -#ifdef OLD_MOVEMENT_CODE cforward = cbackward = false; #endif - // Calculate the angle at which the controls are pointing // to figure out the proper mforward and mbackward. - tempangle = thiscam->angle; + tempangle = movepushangle; tempangle >>= ANGLETOFINESHIFT; - tempx += FixedMul(cmd->forwardmove,FINECOSINE(tempangle)); - tempy += FixedMul(cmd->forwardmove,FINESINE(tempangle)); + tempx += FixedMul(cmd->forwardmove*FRACUNIT,FINECOSINE(tempangle)); + tempy += FixedMul(cmd->forwardmove*FRACUNIT,FINESINE(tempangle)); - tempangle = thiscam->angle-ANGLE_90; + tempangle = movepushsideangle; tempangle >>= ANGLETOFINESHIFT; - tempx += FixedMul(cmd->sidemove,FINECOSINE(tempangle)); - tempy += FixedMul(cmd->sidemove,FINESINE(tempangle)); + tempx += FixedMul(cmd->sidemove*FRACUNIT,FINECOSINE(tempangle)); + tempy += FixedMul(cmd->sidemove*FRACUNIT,FINESINE(tempangle)); - tempx = tempx*FRACUNIT; - tempy = tempy*FRACUNIT; - - controldirection = controllerdirection = - R_PointToAngle2(player->mo->x, player->mo->y, player->mo->x + tempx, - player->mo->y + tempy); - - controlplayerdirection = player->mo->angle; - - if (controlplayerdirection < ANGLE_90) - { - controlplayerdirection += ANGLE_90; - controllerdirection += ANGLE_90; - } - else if (controlplayerdirection >= ANGLE_270) - { - controlplayerdirection -= ANGLE_90; - controllerdirection -= ANGLE_90; - } + controldirection = R_PointToAngle2(0, 0, tempx, tempy); #ifdef OLD_MOVEMENT_CODE - // Controls pointing backwards from player - if (controllerdirection > controlplayerdirection + ANGLE_90 - && controllerdirection < controlplayerdirection - ANGLE_90) - cbackward = true; - else // Controls pointing in player's general direction - cforward = true; + controlplayerdirection = player->mo->angle; + + dangle = controldirection - controlplayerdirection; + + if (dangle > ANGLE_180) //flip to keep to one side + dangle = InvAngle(dangle); + + if (dangle > ANGLE_90) + cbackward = true; // Controls pointing backwards from player + else + cforward = true; // Controls pointing in player's general direction #endif movepushforward = max(abs(cmd->sidemove), abs(cmd->forwardmove)) * (thrustfactor * acceleration); @@ -4581,66 +4543,63 @@ static void P_3dMovement(player_t *player) #endif } } - else + else if (cmd->sidemove && !(player->pflags & PF_GLIDING) && !player->exiting && !P_PlayerInPain(player)) { - if (cmd->sidemove && !(player->pflags & PF_GLIDING) && !player->exiting && !P_PlayerInPain(player)) +#ifdef OLD_MOVEMENT_CODE + boolean mright = 0; + boolean mleft = 0; + angle_t sideangle; + + sideangle = player->mo->angle - ANGLE_90; + + // Monster Iestyn - 04-11-13 + // Quadrants are stupid, excessive and broken, let's do this a much simpler way! + // Get delta angle from rmom angle and player angle first + dangle = R_PointToAngle2(0,0, player->rmomx, player->rmomy) - sideangle; + if (dangle > ANGLE_180) + dangle = InvAngle(dangle); + + // now use it to determine direction! + if (dangle <= ANGLE_45) // angles 0-45 or 315-360 + mright = 1; // going right + else if (dangle >= ANGLE_135) // angles 135-225 + mleft = 1; // going left + + // anything else will leave both at 0, so no need to do anything else +#endif + + movepushside = cmd->sidemove * (thrustfactor * acceleration); + + if (!onground) { -#ifdef OLD_MOVEMENT_CODE - boolean mright = 0; - boolean mleft = 0; - angle_t sideangle; + movepushside >>= 2; - sideangle = player->mo->angle - ANGLE_90; - - // Monster Iestyn - 04-11-13 - // Quadrants are stupid, excessive and broken, let's do this a much simpler way! - // Get delta angle from rmom angle and player angle first - dangle = R_PointToAngle2(0,0, player->rmomx, player->rmomy) - sideangle; - if (dangle > ANGLE_180) - dangle = InvAngle(dangle); - - // now use it to determine direction! - if (dangle <= ANGLE_45) // angles 0-45 or 315-360 - mright = 1; // going right - else if (dangle >= ANGLE_135) // angles 135-225 - mleft = 1; // going left - - // anything else will leave both at 0, so no need to do anything else -#endif - - movepushside = cmd->sidemove * (thrustfactor * acceleration); - - if (!onground) - { + // Reduce movepushslide even more if over "max" flight speed + if (player->powers[pw_tailsfly] && player->speed > topspeed) movepushside >>= 2; - - // Reduce movepushslide even more if over "max" flight speed - if (player->powers[pw_tailsfly] && player->speed > topspeed) - movepushside >>= 2; - } - - // Allow a bit of movement while spinning - if (player->pflags & PF_SPINNING) - { - if (!(player->pflags & PF_STARTDASH)) - movepushside = FixedDiv(movepushside,16*FRACUNIT); - else - movepushside = 0; - } - - // Finally move the player now that his speed/direction has been decided. - movepushside = FixedMul(movepushside, player->mo->scale); -#ifdef OLD_MOVEMENT_CODE - if (player->speed < topspeed) - P_Thrust(player->mo, movepushsideangle, movepushside); - else if (mright && cmd->sidemove < 0) - P_Thrust(player->mo, movepushsideangle, movepushside); - else if (mleft && cmd->sidemove > 0) - P_Thrust(player->mo, movepushsideangle, movepushside); -#else - P_Thrust(player->mo, movepushsideangle, movepushside); -#endif } + + // Allow a bit of movement while spinning + if (player->pflags & PF_SPINNING) + { + if (!(player->pflags & PF_STARTDASH)) + movepushside = FixedDiv(movepushside,16*FRACUNIT); + else + movepushside = 0; + } + + // Finally move the player now that his speed/direction has been decided. + movepushside = FixedMul(movepushside, player->mo->scale); +#ifdef OLD_MOVEMENT_CODE + if (player->speed < topspeed) + P_Thrust(player->mo, movepushsideangle, movepushside); + else if (mright && cmd->sidemove < 0) + P_Thrust(player->mo, movepushsideangle, movepushside); + else if (mleft && cmd->sidemove > 0) + P_Thrust(player->mo, movepushsideangle, movepushside); +#else + P_Thrust(player->mo, movepushsideangle, movepushside); +#endif } #ifndef OLD_MOVEMENT_CODE @@ -4788,6 +4747,7 @@ static void P_ShootLine(mobj_t *source, mobj_t *dest, fixed_t height) static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t radius) { + mobj_t* targ; if (player->pflags & PF_TRANSFERTOCLOSEST) { const angle_t fa = R_PointToAngle2(player->axis1->x, player->axis1->y, player->axis2->x, player->axis2->y); @@ -4800,6 +4760,20 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad player->mo->momy = player->mo->target->y + FixedMul(FINESINE(fa),radius) - player->mo->y; } + if (player->exiting) + return; + + // You're welcome, Rob. -Red + targ = player->mo->target; + if (!P_TryMove(player->mo, player->mo->x+player->mo->momx, player->mo->y+player->mo->momy, true)) + return; + else + P_TeleportMove(player->mo, player->mo->x-player->mo->momx, player->mo->y-player->mo->momy, player->mo->z); + + if (!(player->pflags & PF_TRANSFERTOCLOSEST) && !player->mo->target) { + P_SetTarget(&player->mo->target, targ); + P_SetMobjState(player->mo->tracer, S_SUPERTRANS1); + } { const INT32 sequence = player->mo->target->threshold; mobj_t *transfer1 = NULL; @@ -4812,6 +4786,7 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad boolean transfer1last = false; boolean transfer2last = false; vertex_t vertices[4]; + fixed_t truexspeed = xspeed*(!(player->pflags & PF_TRANSFERTOCLOSEST) && player->mo->target->flags & MF_AMBUSH ? -1 : 1); // Find next waypoint for (th = thinkercap.next; th != &thinkercap; th = th->next) @@ -4918,6 +4893,7 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad CONS_Debug(DBG_NIGHTS, "Transfer1 : %d\n", transfer1->health); CONS_Debug(DBG_NIGHTS, "Transfer2 : %d\n", transfer2->health); } + //CONS_Debug(DBG_NIGHTS, "Xspeed : %d", truexspeed); //CONS_Debug(DBG_NIGHTS, "T1 is at %d, %d\n", transfer1->x>>FRACBITS, transfer1->y>>FRACBITS); //CONS_Debug(DBG_NIGHTS, "T2 is at %d, %d\n", transfer2->x>>FRACBITS, transfer2->y>>FRACBITS); @@ -4928,6 +4904,8 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad if (P_AproxDistance(transfer1->x - player->mo->x, transfer1->y - player->mo->y)>>FRACBITS < P_AproxDistance(transfer2->x - player->mo->x, transfer2->y - player->mo->y)>>FRACBITS) { + //CONS_Debug(DBG_NIGHTS, " must be < 0 to transfer\n"); + if (transfer1->type == MT_AXISTRANSFERLINE) { if (transfer1last) @@ -4960,7 +4938,8 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad transfer1line.dy = transfer1line.v2->y - transfer1line.v1->y; if (P_PointOnLineSide(player->mo->x, player->mo->y, &transfer1line) - != P_PointOnLineSide(player->mo->x+player->mo->momx, player->mo->y+player->mo->momy, &transfer1line)) + != P_PointOnLineSide(player->mo->x+player->mo->momx, player->mo->y+player->mo->momy, &transfer1line) + && truexspeed < 0) { if (cv_debug & DBG_NIGHTS) { @@ -5015,7 +4994,8 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad transfer1line.dy = transfer1line.v2->y - transfer1line.v1->y; if (P_PointOnLineSide(player->mo->x, player->mo->y, &transfer1line) - != P_PointOnLineSide(player->mo->x+player->mo->momx, player->mo->y+player->mo->momy, &transfer1line)) + != P_PointOnLineSide(player->mo->x+player->mo->momx, player->mo->y+player->mo->momy, &transfer1line) + && truexspeed < 0) { if (cv_debug & DBG_NIGHTS) { @@ -5044,6 +5024,7 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad } else { + //CONS_Debug(DBG_NIGHTS, " must be > 0 to transfer\n"); if (transfer2->type == MT_AXISTRANSFERLINE) { if (transfer2last) @@ -5079,7 +5060,8 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad transfer2line.dy = transfer2line.v2->y - transfer2line.v1->y; if (P_PointOnLineSide(player->mo->x, player->mo->y, &transfer2line) - != P_PointOnLineSide(player->mo->x+player->mo->momx, player->mo->y+player->mo->momy, &transfer2line)) + != P_PointOnLineSide(player->mo->x+player->mo->momx, player->mo->y+player->mo->momy, &transfer2line) + && truexspeed > 0) { if (cv_debug & DBG_NIGHTS) { @@ -5144,7 +5126,8 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad transfer2line.dy = transfer2line.v2->y - transfer2line.v1->y; if (P_PointOnLineSide(player->mo->x, player->mo->y, &transfer2line) - != P_PointOnLineSide(player->mo->x+player->mo->momx, player->mo->y+player->mo->momy, &transfer2line)) + != P_PointOnLineSide(player->mo->x+player->mo->momx, player->mo->y+player->mo->momy, &transfer2line) + && truexspeed > 0) { if (cv_debug & DBG_NIGHTS) { @@ -5288,7 +5271,7 @@ static void P_DoNiGHTSCapsule(player_t *player) P_SetMobjState(emmo, mobjinfo[MT_GOTEMERALD].meleestate + em); }*/ - if (player->mo->tracer) // \todo: find some way to make NiGHTS special stages completable for non-NiGHTS players, if the special stage allows it + if (player->mo->tracer) { // Only give it to ONE person, and THAT player has to get to the goal! emmo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + player->mo->info->height, MT_GOTEMERALD); @@ -5481,47 +5464,6 @@ static void P_NiGHTSMovement(player_t *player) player->mo->flags2 |= MF2_DONTDRAW; P_SetScale(player->mo->tracer, player->mo->scale); - // Check for flipped 'gravity' - { - boolean no3dfloorgrav = true; // Custom gravity - - player->mo->eflags &= ~MFE_VERTICALFLIP; - - if (player->mo->subsector->sector->ffloors) // Check for 3D floor gravity too. - { - ffloor_t *rover; - - for (rover = player->mo->subsector->sector->ffloors; rover; rover = rover->next) - { - if (!(rover->flags & FF_EXISTS)) - continue; - - if (P_InsideANonSolidFFloor(player->mo, rover)) - { - if (rover->master->frontsector->gravity) - { - if (rover->master->frontsector->verticalflip) - player->mo->eflags |= MFE_VERTICALFLIP; - - no3dfloorgrav = false; - break; - } - } - } - } - - if (no3dfloorgrav) - { - if (player->mo->subsector->sector->verticalflip) - player->mo->eflags |= MFE_VERTICALFLIP; - } - } - - if (player->mo->eflags & MFE_VERTICALFLIP) - player->mo->tracer->eflags |= MFE_VERTICALFLIP; - else - player->mo->tracer->eflags &= ~MFE_VERTICALFLIP; - if (player->mo->eflags & MFE_VERTICALFLIP) cmd->forwardmove = (SINT8)(-cmd->forwardmove); @@ -5596,10 +5538,15 @@ static void P_NiGHTSMovement(player_t *player) mobj_t *firstmobj; mobj_t *secondmobj; fixed_t spawndist = FixedMul(16*FRACUNIT, player->mo->scale); + fixed_t z = player->mo->z + player->mo->height/2; - firstmobj = P_SpawnMobj(player->mo->x + P_ReturnThrustX(player->mo, player->mo->angle+ANGLE_90, spawndist), player->mo->y + P_ReturnThrustY(player->mo, player->mo->angle+ANGLE_90, spawndist), player->mo->z + player->mo->height/2, MT_NIGHTSPARKLE); - secondmobj = P_SpawnMobj(player->mo->x + P_ReturnThrustX(player->mo, player->mo->angle-ANGLE_90, spawndist), player->mo->y + P_ReturnThrustY(player->mo, player->mo->angle-ANGLE_90, spawndist), player->mo->z + player->mo->height/2, MT_NIGHTSPARKLE); + if (player->mo->eflags & MFE_VERTICALFLIP) + z -= FixedMul(mobjinfo[MT_NIGHTSPARKLE].height, player->mo->scale); + firstmobj = P_SpawnMobj(player->mo->x + P_ReturnThrustX(player->mo, player->mo->angle+ANGLE_90, spawndist), player->mo->y + P_ReturnThrustY(player->mo, player->mo->angle+ANGLE_90, spawndist), z, MT_NIGHTSPARKLE); + secondmobj = P_SpawnMobj(player->mo->x + P_ReturnThrustX(player->mo, player->mo->angle-ANGLE_90, spawndist), player->mo->y + P_ReturnThrustY(player->mo, player->mo->angle-ANGLE_90, spawndist), z, MT_NIGHTSPARKLE); + + firstmobj->destscale = secondmobj->destscale = player->mo->scale; P_SetTarget(&firstmobj->target, player->mo); P_SetScale(firstmobj, player->mo->scale); P_SetTarget(&secondmobj->target, player->mo); @@ -5788,6 +5735,14 @@ static void P_NiGHTSMovement(player_t *player) P_NightsTransferPoints(player, xspeed, radius); + // Check here after transferring because the game can be dumb sometimes -Red + if (player->mo->tracer->state >= &states[S_SUPERTRANS1] + && player->mo->tracer->state <= &states[S_SUPERTRANS9]) + { + player->mo->momx = player->mo->momy = player->mo->momz = 0; + return; + } + if (still) player->mo->momz = -FRACUNIT; else @@ -5799,36 +5754,27 @@ static void P_NiGHTSMovement(player_t *player) player->mo->momz = -20*FRACUNIT; // You can create splashes as you fly across water. - if (player->mo->z + P_GetPlayerHeight(player) >= player->mo->watertop && player->mo->z <= player->mo->watertop && player->speed > 9000 - && leveltime % (TICRATE/7) == 0 && !player->spectator) + if (((!(player->mo->eflags & MFE_VERTICALFLIP) + && player->mo->z + P_GetPlayerHeight(player) >= player->mo->watertop && player->mo->z <= player->mo->watertop) + || (player->mo->eflags & MFE_VERTICALFLIP + && player->mo->z + player->mo->height - P_GetPlayerHeight(player) <= player->mo->waterbottom && player->mo->z + player->mo->height >= player->mo->waterbottom)) + && player->speed > 9000 && leveltime % (TICRATE/7) == 0 && !player->spectator) { - mobj_t *water = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->watertop, MT_SPLISH); + mobj_t *water = P_SpawnMobj(player->mo->x, player->mo->y, + ((player->mo->eflags & MFE_VERTICALFLIP) ? player->mo->waterbottom - FixedMul(mobjinfo[MT_SPLISH].height, player->mo->scale) : player->mo->watertop), MT_SPLISH); if (player->mo->eflags & MFE_GOOWATER) S_StartSound(water, sfx_ghit); else S_StartSound(water, sfx_wslap); + if (player->mo->eflags & MFE_VERTICALFLIP) + { + water->flags2 |= MF2_OBJECTFLIP; + water->eflags |= MFE_VERTICALFLIP; + } water->destscale = player->mo->scale; P_SetScale(water, player->mo->scale); } - // Spawn Sonic's bubbles - if (player->mo->eflags & MFE_UNDERWATER && !player->spectator) - { - const fixed_t zh = player->mo->z + FixedDiv(player->mo->height, 5*(FRACUNIT/4)); - mobj_t *bubble = NULL; - if (!(P_Random() % 16)) - bubble = P_SpawnMobj(player->mo->x, player->mo->y, zh, MT_SMALLBUBBLE); - else if (!(P_Random() % 96)) - bubble = P_SpawnMobj(player->mo->x, player->mo->y, zh, MT_MEDIUMBUBBLE); - - if (bubble) - { - bubble->threshold = 42; - bubble->destscale = player->mo->scale; - P_SetScale(bubble,player->mo->scale); - } - } - if (player->mo->momx || player->mo->momy) player->mo->angle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); @@ -5850,7 +5796,7 @@ static void P_NiGHTSMovement(player_t *player) else if (player->angle_pos > player->old_angle_pos) neg = -1; - movingangle = R_PointToAngle2(0, player->mo->z, neg*R_PointToDist2(player->mo->momx, player->mo->momy, 0, 0), player->mo->z + player->mo->momz); + movingangle = R_PointToAngle2(0, 0, neg*R_PointToDist2(player->mo->momx, player->mo->momy, 0, 0), player->mo->momz); player->anotherflyangle = (movingangle >> ANGLETOFINESHIFT) * 360/FINEANGLES; } @@ -5963,8 +5909,6 @@ static void P_NiGHTSMovement(player_t *player) } } - P_CheckSneakerAndLivesTimer(player); - if (objectplacing) OP_NightsObjectplace(player); } @@ -6040,61 +5984,44 @@ void P_ElementalFireTrail(player_t *player) fixed_t ground; mobj_t *flame; angle_t travelangle; + INT32 i; I_Assert(player != NULL); I_Assert(player->mo != NULL); I_Assert(!P_MobjWasRemoved(player->mo)); if (player->mo->eflags & MFE_VERTICALFLIP) - ground = player->mo->ceilingz - mobjinfo[MT_SPINFIRE].height - 1; + ground = player->mo->ceilingz - FixedMul(mobjinfo[MT_SPINFIRE].height, player->mo->scale); else - ground = player->mo->floorz + 1; + ground = player->mo->floorz; - travelangle = R_PointToAngle2(player->mo->x, player->mo->y, player->rmomx + player->mo->x, player->rmomy + player->mo->y); + travelangle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy); - newx = player->mo->x + P_ReturnThrustX(player->mo, travelangle + ANGLE_135, FixedMul(24*FRACUNIT, player->mo->scale)); - newy = player->mo->y + P_ReturnThrustY(player->mo, travelangle + ANGLE_135, FixedMul(24*FRACUNIT, player->mo->scale)); - flame = P_SpawnMobj(newx, newy, ground, MT_SPINFIRE); - P_SetTarget(&flame->target, player->mo); - flame->angle = travelangle; - flame->fuse = TICRATE*6; - flame->destscale = player->mo->scale; - P_SetScale(flame, player->mo->scale); - if (player->mo->eflags & MFE_VERTICALFLIP) - flame->eflags |= MFE_VERTICALFLIP; - - flame->momx = 8; - P_XYMovement(flame); - - if (player->mo->eflags & MFE_VERTICALFLIP) + for (i = 0; i < 2; i++) { - if (flame->z + flame->height < flame->ceilingz-1) + newx = player->mo->x + P_ReturnThrustX(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(24*FRACUNIT, player->mo->scale)); + newy = player->mo->y + P_ReturnThrustY(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(24*FRACUNIT, player->mo->scale)); + flame = P_SpawnMobj(newx, newy, ground, MT_SPINFIRE); + P_SetTarget(&flame->target, player->mo); + flame->angle = travelangle; + flame->fuse = TICRATE*6; + flame->destscale = player->mo->scale; + P_SetScale(flame, player->mo->scale); + flame->eflags = (flame->eflags & ~MFE_VERTICALFLIP)|(player->mo->eflags & MFE_VERTICALFLIP); + + flame->momx = 8; + P_XYMovement(flame); + if (P_MobjWasRemoved(flame)) + continue; + + if (player->mo->eflags & MFE_VERTICALFLIP) + { + if (flame->z + flame->height < flame->ceilingz) + P_RemoveMobj(flame); + } + else if (flame->z > flame->floorz) P_RemoveMobj(flame); } - else if (flame->z > flame->floorz+1) - P_RemoveMobj(flame); - - newx = player->mo->x + P_ReturnThrustX(player->mo, travelangle - ANGLE_135, FixedMul(24*FRACUNIT, player->mo->scale)); - newy = player->mo->y + P_ReturnThrustY(player->mo, travelangle - ANGLE_135, FixedMul(24*FRACUNIT, player->mo->scale)); - flame = P_SpawnMobj(newx, newy, ground, MT_SPINFIRE); - P_SetTarget(&flame->target, player->mo); - flame->angle = travelangle; - flame->fuse = TICRATE*6; - flame->destscale = player->mo->scale; - P_SetScale(flame, player->mo->scale); - if (player->mo->eflags & MFE_VERTICALFLIP) - flame->eflags |= MFE_VERTICALFLIP; - - flame->momx = 8; - P_XYMovement(flame); - - if (player->mo->eflags & MFE_VERTICALFLIP) - { - if (flame->z + flame->height < flame->ceilingz-1) - P_RemoveMobj(flame); - } - else if (flame->z > flame->floorz+1) - P_RemoveMobj(flame); } static void P_SkidStuff(player_t *player) @@ -6158,7 +6085,8 @@ static void P_SkidStuff(player_t *player) } } else if (P_AproxDistance(pmx, pmy) >= FixedMul(player->runspeed/2, player->mo->scale) // if you were moving faster than half your run speed last frame - && (player->mo->momx != pmx || player->mo->momy != pmy)) // and you are moving differently this frame + && (player->mo->momx != pmx || player->mo->momy != pmy) // and you are moving differently this frame + && P_GetPlayerControlDirection(player) == 2) // and your controls are pointing in the opposite direction to your movement { // check for skidding angle_t mang = R_PointToAngle2(0,0,pmx,pmy); // movement angle angle_t pang = R_PointToAngle2(pmx,pmy,player->mo->momx,player->mo->momy); // push angle @@ -6188,16 +6116,11 @@ static void P_SkidStuff(player_t *player) // // P_MovePlayer -// -// todo: This seriously needs to be split up. -// 913 lines of code in this function. static void P_MovePlayer(player_t *player) { ticcmd_t *cmd; INT32 i; - fixed_t tempx, tempy; - angle_t tempangle; camera_t *thiscam; fixed_t runspd; @@ -6211,8 +6134,6 @@ static void P_MovePlayer(player_t *player) if (player->mo->state >= &states[S_PLAY_SUPERTRANS1] && player->mo->state <= &states[S_PLAY_SUPERTRANS9]) { - P_CheckSneakerAndLivesTimer(player); - P_CheckUnderwaterAndSpaceTimer(player); player->mo->momx = player->mo->momy = player->mo->momz = 0; return; } @@ -6220,109 +6141,6 @@ static void P_MovePlayer(player_t *player) cmd = &player->cmd; runspd = FixedMul(player->runspeed, player->mo->scale); - if ((netgame || splitscreen) && player->spectator && (cmd->buttons & BT_ATTACK) && !player->powers[pw_flashing]) - { - if (!cv_allowteamchange.value) - { - if (P_IsLocalPlayer(player)) - CONS_Printf(M_GetText("Server does not allow team change.\n")); - player->powers[pw_flashing] += 2*TICRATE; //to prevent message spam. - } - - // Team changing in Team Match and CTF - // Pressing fire assigns you to a team that needs players if allowed. - // Partial code reproduction from p_tick.c autobalance code. - else if (G_GametypeHasTeams()) - { - INT32 changeto = 0; - INT32 z, numplayersred = 0, numplayersblue = 0; - - //find a team by num players, score, or random if all else fails. - for (z = 0; z < MAXPLAYERS; ++z) - if (playeringame[z]) - { - if (players[z].ctfteam == 1) - ++numplayersred; - else if (players[z].ctfteam == 2) - ++numplayersblue; - } - // for z - - if (numplayersblue > numplayersred) - changeto = 1; - else if (numplayersred > numplayersblue) - changeto = 2; - else if (bluescore > redscore) - changeto = 1; - else if (redscore > bluescore) - changeto = 2; - else - changeto = (P_Random() & 1) + 1; - - if (player->mo) - { - P_RemoveMobj(player->mo); - player->mo = NULL; - } - player->spectator = false; - player->ctfteam = changeto; - player->playerstate = PST_REBORN; - - //Reset away view - if (P_IsLocalPlayer(player) && displayplayer != consoleplayer) - displayplayer = consoleplayer; - - if (changeto == 1) - CONS_Printf(M_GetText("%s switched to the %c%s%c.\n"), player_names[player-players], '\x85', M_GetText("Red Team"), '\x80'); - else if (changeto == 2) - CONS_Printf(M_GetText("%s switched to the %c%s%c.\n"), player_names[player-players], '\x84', M_GetText("Blue Team"), '\x80'); - - return; // no more player->mo, cannot continue. - } - - // Joining in game from firing. - else - { - // Exception for hide and seek. Don't join a game when you simply - // respawn in place and sit there for the rest of the round. - if (!(gametype == GT_HIDEANDSEEK && leveltime > (hidetime * TICRATE))) - { - if (player->mo) - { - P_RemoveMobj(player->mo); - player->mo = NULL; - } - player->spectator = false; - player->playerstate = PST_REBORN; - - if (gametype == GT_TAG) - { - //Make joining players "it" after hidetime. - if (leveltime > (hidetime * TICRATE)) - { - CONS_Printf(M_GetText("%s is now IT!\n"), player_names[player-players]); // Tell everyone who is it! - player->pflags |= PF_TAGIT; - } - - P_CheckSurvivors(); - } - - //Reset away view - if (P_IsLocalPlayer(player) && displayplayer != consoleplayer) - displayplayer = consoleplayer; - - CONS_Printf(M_GetText("%s entered the game.\n"), player_names[player-players]); - return; // no more player->mo, cannot continue. - } - else - { - if (P_IsLocalPlayer(player)) - CONS_Printf(M_GetText("You must wait until next round to enter the game.\n")); - player->powers[pw_flashing] += 2*TICRATE; //to prevent message spam. - } - } - } - // Control relinquishing stuff! if (player->powers[pw_ingoop]) player->pflags |= PF_FULLSTASIS; @@ -6369,48 +6187,14 @@ static void P_MovePlayer(player_t *player) } } - // Even if not NiGHTS, pull in nearby objects when walking around as John Q. Elliot. - if (!objectplacing && !((netgame || multiplayer) && player->spectator) - && ((maptol & TOL_NIGHTS)) && (!(player->pflags & PF_NIGHTSMODE) || player->powers[pw_nights_helper])) + if (player->spectator) { - thinker_t *th; - mobj_t *mo2; - fixed_t x = player->mo->x; - fixed_t y = player->mo->y; - fixed_t z = player->mo->z; - - for (th = thinkercap.next; th != &thinkercap; th = th->next) - { - if (th->function.acp1 != (actionf_p1)P_MobjThinker) - continue; - - mo2 = (mobj_t *)th; - - if (!(mo2->type == MT_NIGHTSWING || mo2->type == MT_RING || mo2->type == MT_COIN -#ifdef BLUE_SPHERES - || mo2->type == MT_BLUEBALL -#endif - )) - continue; - - if (P_AproxDistance(P_AproxDistance(mo2->x - x, mo2->y - y), mo2->z - z) > FixedMul(128*FRACUNIT, player->mo->scale)) - continue; - - // Yay! The thing's in reach! Pull it in! - mo2->flags |= MF_NOCLIP|MF_NOCLIPHEIGHT; - mo2->flags2 |= MF2_NIGHTSPULL; - P_SetTarget(&mo2->tracer, player->mo); - } - } - - if (player->linktimer && !player->powers[pw_nights_linkfreeze]) - { - if (--player->linktimer <= 0) // Link timer - player->linkcount = 0; + P_SpectatorMovement(player); + return; } // Locate the capsule for this mare. - if (maptol & TOL_NIGHTS) + else if (maptol & TOL_NIGHTS) { if (!player->capsule && !player->bonustime) { @@ -6449,7 +6233,7 @@ static void P_MovePlayer(player_t *player) return; } - if ((player->pflags & PF_NIGHTSFALL) && P_IsObjectOnGround(player->mo)) + if (player->pflags & PF_NIGHTSFALL && P_IsObjectOnGround(player->mo)) { if (G_IsSpecialStage(gamemap)) { @@ -6465,26 +6249,16 @@ static void P_MovePlayer(player_t *player) } } - else if (player->spectator) - { - P_SpectatorMovement(player); - return; - } - ////////////////////// // MOVEMENT CODE // ////////////////////// - if (twodlevel || (player->mo->flags2 & MF2_TWOD)) // 2d-level, so special control applies. + if (twodlevel || player->mo->flags2 & MF2_TWOD) // 2d-level, so special control applies. P_2dMovement(player); else { - if (!player->climbing && (netgame || (player == &players[consoleplayer] - && !cv_analog.value) || (player == &players[secondarydisplayplayer] && !cv_analog2.value) - || (player->pflags & PF_SPINNING))) - { + if (!player->climbing && (!P_AnalogMove(player) || player->pflags & PF_SPINNING)) player->mo->angle = (cmd->angleturn<<16 /* not FRACBITS */); - } ticruned++; if ((cmd->angleturn & TICCMD_RECEIVED) == 0) @@ -6553,6 +6327,23 @@ static void P_MovePlayer(player_t *player) else if (player->dashspeed > 0 && player->dashspeed < FixedMul(player->mindash, player->mo->scale)) player->dashspeed = FixedMul(player->mindash, player->mo->scale); + if (!(player->charability == CA_GLIDEANDCLIMB) || player->gotflag) // If you can't glide, then why the heck would you be gliding? + { + if (player->pflags & PF_GLIDING || player->climbing) + { + if (onground) + P_SetPlayerMobjState(player->mo, S_PLAY_RUN1); + else + { + player->pflags |= PF_JUMPED; + P_SetPlayerMobjState(player->mo, S_PLAY_ATK1); + } + } + player->pflags &= ~PF_GLIDING; + player->glidetime = 0; + player->climbing = 0; + } + // Glide MOMZ // AKA my own gravity. =) if (player->pflags & PF_GLIDING) @@ -6597,7 +6388,9 @@ static void P_MovePlayer(player_t *player) if (!(player->pflags & PF_JUMPDOWN)) // If not holding the jump button { P_ResetPlayer(player); // down, stop gliding. - if ((player->charability2 == CA2_MULTIABILITY) + if (onground) + P_SetPlayerMobjState(player->mo, S_PLAY_RUN1); + else if ((player->charability2 == CA2_MULTIABILITY) || (player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds]) && player->charability == CA_GLIDEANDCLIMB)) { player->pflags |= PF_JUMPED; @@ -6628,13 +6421,6 @@ static void P_MovePlayer(player_t *player) } } - if (!(player->charability == CA_GLIDEANDCLIMB)) // If you can't glide, then why the heck would you be gliding? - { - player->pflags &= ~PF_GLIDING; - player->glidetime = 0; - player->climbing = 0; - } - // If you're running fast enough, you can create splashes as you run in shallow water. if (!player->climbing && ((!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + player->mo->height >= player->mo->watertop && player->mo->z <= player->mo->watertop) @@ -6664,63 +6450,34 @@ static void P_MovePlayer(player_t *player) S_StartSound(player->mo, sfx_floush); } -#if 1 - // "Blur" a bit when you have speed shoes and are going fast enough - if ((player->powers[pw_super] || player->powers[pw_sneakers]) && (player->speed + abs(player->mo->momz)) > FixedMul(20*FRACUNIT,player->mo->scale)) - { - mobj_t *gmobj = P_SpawnGhostMobj(player->mo); - gmobj->fuse = 2; - if (leveltime & 1) - { - gmobj->frame &= ~FF_TRANSMASK; - gmobj->frame |= tr_trans70<flags2 |= MF2_DONTDRAW; - } -#endif - - ////////////////////////////////////////////////////// - // P_GivePlayerRings now handles Extra Life Bonuses // - ////////////////////////////////////////////////////// - - ////////////////////////// - // SUPER SONIC STUFF // - ////////////////////////// - - P_DoSuperStuff(player); - - ///////////////////////// - //Special Music Changes// - ///////////////////////// - - P_CheckSneakerAndLivesTimer(player); - - /////////////////////////////////////////////////////// - //LOTS OF UNDERWATER CODE (Well, used to be, anyway) // - /////////////////////////////////////////////////////// - - // Spawn Sonic's bubbles - P_DoBubbleBreath(player); - - // Display the countdown drown numbers! - P_CheckUnderwaterAndSpaceTimer(player); - //////////////// //TAILS FLYING// //////////////// + if (!(player->charability == CA_FLY || player->charability == CA_SWIM)) // why are you flying when you cannot fly?! + { + if (player->powers[pw_tailsfly] + || (player->mo->state >= &states[S_PLAY_SPC1] && player->mo->state <= &states[S_PLAY_SPC4])) + { + if (onground) + P_SetPlayerMobjState(player->mo, S_PLAY_RUN1); + else + { + player->pflags |= PF_JUMPED; + P_SetPlayerMobjState(player->mo, S_PLAY_ATK1); + } + } + player->powers[pw_tailsfly] = 0; + } + + if (player->gotflag && player->powers[pw_tailsfly]) + player->powers[pw_tailsfly] = 1; + // If not in a fly position, don't think you're flying! if (player->panim != PA_ABILITY) player->powers[pw_tailsfly] = 0; - if (!(player->pflags & PF_STASIS) && (player->charability == CA_FLY || (player->charability == CA_SWIM && (player->mo->eflags & MFE_UNDERWATER)))) + if (player->charability == CA_FLY || (player->charability == CA_SWIM && player->mo->eflags & MFE_UNDERWATER)) { // Fly counter for Tails. if (player->powers[pw_tailsfly]) @@ -6730,7 +6487,7 @@ static void P_MovePlayer(player_t *player) if (player->charability2 == CA2_MULTIABILITY) { // Adventure-style flying by just holding the button down - if (cmd->buttons & BT_JUMP) + if (cmd->buttons & BT_JUMP && !(player->pflags & PF_STASIS) && !player->exiting) P_SetObjectMomZ(player->mo, actionspd/4, true); } else @@ -6750,7 +6507,7 @@ static void P_MovePlayer(player_t *player) S_StartSound(player->mo, sfx_putput); // Descend - if (cmd->buttons & BT_USE) + if (cmd->buttons & BT_USE && !(player->pflags & PF_STASIS) && !player->exiting) if (P_MobjFlip(player->mo)*player->mo->momz > -FixedMul(5*actionspd, player->mo->scale)) P_SetObjectMomZ(player->mo, -actionspd/2, true); @@ -6769,9 +6526,6 @@ static void P_MovePlayer(player_t *player) } } - // Spawn Invincibility Sparkles - P_CheckInvincibilityTimer(player); - // End your chain if you're on the ground or climbing a wall. // But not if invincible! Allow for some crazy long chains with it. // Also keep in mind the PF_JUMPED check. @@ -6814,43 +6568,41 @@ static void P_MovePlayer(player_t *player) if (!(player->pflags & PF_SPINNING)) player->pflags &= ~PF_STARTDASH; - // spawn stuff over your head! - P_DoPlayerHeadSigns(player); - ////////////////// //ANALOG CONTROL// ////////////////// - if (!netgame && ((player == &players[consoleplayer] && cv_analog.value) || (player == &players[secondarydisplayplayer] && cv_analog2.value)) - && (cmd->forwardmove != 0 || cmd->sidemove != 0) && !player->climbing && !twodlevel && !(player->mo && (player->mo->flags2 & MF2_TWOD))) + // This really looks like it should be moved to P_3dMovement. -Red + if (P_AnalogMove(player) && thiscam->chase + && (cmd->forwardmove != 0 || cmd->sidemove != 0) && !player->climbing && !twodlevel && !(player->mo->flags2 & MF2_TWOD)) { // If travelling slow enough, face the way the controls // point and not your direction of movement. - if (player->speed < FixedMul(5*FRACUNIT, player->mo->scale) || player->pflags & PF_GLIDING - || (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z > player->mo->floorz) - || (player->mo->eflags & MFE_VERTICALFLIP && player->mo->z+player->mo->height < player->mo->ceilingz)) + if (player->speed < FixedMul(5*FRACUNIT, player->mo->scale) || player->pflags & PF_GLIDING || !onground) { - tempx = tempy = 0; + fixed_t tempx = 0, tempy = 0; + angle_t tempangle; - tempangle = thiscam->angle; + if (player->awayviewtics) + tempangle = player->awayviewmobj->angle; + else + tempangle = thiscam->angle; tempangle >>= ANGLETOFINESHIFT; - tempx += FixedMul(cmd->forwardmove,FINECOSINE(tempangle)); - tempy += FixedMul(cmd->forwardmove,FINESINE(tempangle)); + tempx += FixedMul(cmd->forwardmove*FRACUNIT,FINECOSINE(tempangle)); + tempy += FixedMul(cmd->forwardmove*FRACUNIT,FINESINE(tempangle)); - tempangle = thiscam->angle-ANGLE_90; + tempangle <<= ANGLETOFINESHIFT; + tempangle -= ANGLE_90; tempangle >>= ANGLETOFINESHIFT; - tempx += FixedMul(cmd->sidemove,FINECOSINE(tempangle)); - tempy += FixedMul(cmd->sidemove,FINESINE(tempangle)); + tempx += FixedMul(cmd->sidemove*FRACUNIT,FINECOSINE(tempangle)); + tempy += FixedMul(cmd->sidemove*FRACUNIT,FINESINE(tempangle)); - tempx = tempx*FRACUNIT; - tempy = tempy*FRACUNIT; - - player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, player->mo->x + tempx, player->mo->y + tempy); + player->mo->angle = R_PointToAngle2(0, 0, tempx, tempy); } // Otherwise, face the direction you're travelling. else if (player->panim == PA_WALK || player->panim == PA_RUN || player->panim == PA_ROLL || ((player->mo->state >= &states[S_PLAY_ABL1] && player->mo->state <= &states[S_PLAY_SPC4]) && player->charability == CA_FLY)) - player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, player->rmomx + player->mo->x, player->rmomy + player->mo->y); + player->mo->angle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy); // Update the local angle control. if (player == &players[consoleplayer]) @@ -7026,7 +6778,7 @@ static void P_MovePlayer(player_t *player) fixed_t speed; const fixed_t runnyspeed = 20*FRACUNIT; - speed = R_PointToDist2(player->mo->x + player->rmomx, player->mo->y + player->rmomy, player->mo->x, player->mo->y); + speed = R_PointToDist2(player->rmomx, player->rmomy, 0, 0); if (speed > player->normalspeed-5*FRACUNIT) speed = player->normalspeed-5*FRACUNIT; @@ -7034,13 +6786,13 @@ static void P_MovePlayer(player_t *player) if (speed >= runnyspeed) player->fovadd = speed-runnyspeed; else - player->fovadd = 0*FRACUNIT; + player->fovadd = 0; - if (player->fovadd < 0*FRACUNIT) - player->fovadd = 0*FRACUNIT; + if (player->fovadd < 0) + player->fovadd = 0; } else - player->fovadd = 0*FRACUNIT; + player->fovadd = 0; #endif #ifdef FLOORSPLATS @@ -7489,6 +7241,9 @@ void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius) if (!G_RingSlingerGametype() && mo->type == MT_PLAYER) continue; // Don't hurt players in Co-Op! + if (abs(inflictor->x - mo->x) > radius || abs(inflictor->y - mo->y) > radius || abs(inflictor->z - mo->z) > radius) + continue; // Workaround for possible integer overflow in the below -Red + if (P_AproxDistance(P_AproxDistance(inflictor->x - mo->x, inflictor->y - mo->y), inflictor->z - mo->z) > radius) continue; @@ -7587,6 +7342,7 @@ boolean P_LookForEnemies(player_t *player) void P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target { fixed_t dist; + fixed_t ns = 0; if (!enemy) return; @@ -7612,35 +7368,20 @@ void P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target dist = 1; if (source->type == MT_DETON && enemy->player) // For Deton Chase (Unused) - { - fixed_t ns = FixedDiv(FixedMul(enemy->player->normalspeed, enemy->scale), FixedDiv(20*FRACUNIT,17*FRACUNIT)); - source->momx = FixedMul(FixedDiv(enemy->x - source->x, dist), ns); - source->momy = FixedMul(FixedDiv(enemy->y - source->y, dist), ns); - source->momz = FixedMul(FixedDiv(enemy->z - source->z, dist), ns); - } + ns = FixedDiv(FixedMul(enemy->player->normalspeed, enemy->scale), FixedDiv(20*FRACUNIT,17*FRACUNIT)); else if (source->type != MT_PLAYER) { if (source->threshold == 32000) - { - fixed_t ns = FixedMul(source->info->speed/2, source->scale); - source->momx = FixedMul(FixedDiv(enemy->x - source->x, dist), ns); - source->momy = FixedMul(FixedDiv(enemy->y - source->y, dist), ns); - source->momz = FixedMul(FixedDiv(enemy->z - source->z, dist), ns); - } + ns = FixedMul(source->info->speed/2, source->scale); else - { - source->momx = FixedMul(FixedDiv(enemy->x - source->x, dist), FixedMul(source->info->speed, source->scale)); - source->momy = FixedMul(FixedDiv(enemy->y - source->y, dist), FixedMul(source->info->speed, source->scale)); - source->momz = FixedMul(FixedDiv(enemy->z - source->z, dist), FixedMul(source->info->speed, source->scale)); - } + ns = FixedMul(source->info->speed, source->scale); } else if (source->player) - { - const fixed_t ns = FixedMul(source->player->actionspd, source->player->mo->scale); - source->momx = FixedMul(FixedDiv(enemy->x - source->x, dist), FixedDiv(ns,3*FRACUNIT/2)); - source->momy = FixedMul(FixedDiv(enemy->y - source->y, dist), FixedDiv(ns,3*FRACUNIT/2)); - source->momz = FixedMul(FixedDiv(enemy->z - source->z, dist), FixedDiv(ns,3*FRACUNIT/2)); - } + ns = FixedDiv(FixedMul(source->player->actionspd, source->scale), 3*FRACUNIT/2); + + source->momx = FixedMul(FixedDiv(enemy->x - source->x, dist), ns); + source->momy = FixedMul(FixedDiv(enemy->y - source->y, dist), ns); + source->momz = FixedMul(FixedDiv(enemy->z - source->z, dist), ns); } // Search for emeralds @@ -7964,25 +7705,12 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall if (P_CameraThinker(player, thiscam, resetcalled)) return true; - if (player->pflags & PF_NIGHTSMODE) - { - if (splitscreen && player == &players[secondarydisplayplayer]) - CV_SetValue(&cv_cam2_dist, 320); - else if (player == &players[displayplayer]) - CV_SetValue(&cv_cam_dist, 320); - } - if (thiscam == &camera) { camspeed = cv_cam_speed.value; camstill = cv_cam_still.value; camrotate = cv_cam_rotate.value; - - if (player->pflags & PF_NIGHTSMODE) - camdist = cv_cam_dist.value; - else - camdist = FixedMul(cv_cam_dist.value, mo->scale); - + camdist = FixedMul(cv_cam_dist.value, mo->scale); camheight = FixedMul(cv_cam_height.value, mo->scale); } else // Camera 2 @@ -7990,12 +7718,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall camspeed = cv_cam2_speed.value; camstill = cv_cam2_still.value; camrotate = cv_cam2_rotate.value; - - if (player->pflags & PF_NIGHTSMODE) - camdist = cv_cam2_dist.value; - else - camdist = FixedMul(cv_cam2_dist.value, mo->scale); - + camdist = FixedMul(cv_cam2_dist.value, mo->scale); camheight = FixedMul(cv_cam2_height.value, mo->scale); } @@ -8033,11 +7756,8 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall localangle -= abs(focusangle - localangle)>>5; } } - else if ((player == &players[consoleplayer] && cv_analog.value) - || (player == &players[secondarydisplayplayer] && cv_analog2.value)) // Analog - { + else if (P_AnalogMove(player)) // Analog angle = R_PointToAngle2(thiscam->x, thiscam->y, mo->x, mo->y); - } else angle = focusangle + FixedAngle(camrotate*FRACUNIT); @@ -8091,11 +7811,13 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall // sets ideal cam pos if (twodlevel || (mo->flags2 & MF2_TWOD)) dist = 480<pflags & PF_NIGHTSMODE) + dist = 320<climbing || (player->exiting && !(player->pflags & PF_NIGHTSMODE)) || player->playerstate == PST_DEAD || (player->pflags & (PF_MACESPIN|PF_ITEMHANG|PF_ROPEHANG))) + if (player->climbing || player->exiting || player->playerstate == PST_DEAD || (player->pflags & (PF_MACESPIN|PF_ITEMHANG|PF_ROPEHANG))) dist <<= 1; } @@ -8159,7 +7881,12 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall // Cameras use the heightsec's heights rather then the actual sector heights. // If you can see through it, why not move the camera through it too? - if (newsubsec->sector->heightsec >= 0) + if (newsubsec->sector->camsec >= 0) + { + myfloorz = sectors[newsubsec->sector->camsec].floorheight; + myceilingz = sectors[newsubsec->sector->camsec].ceilingheight; + } + else if (newsubsec->sector->heightsec >= 0) { myfloorz = sectors[newsubsec->sector->heightsec].floorheight; myceilingz = sectors[newsubsec->sector->heightsec].ceilingheight; @@ -8446,11 +8173,133 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall return (x == thiscam->x && y == thiscam->y && z == thiscam->z && angle == thiscam->aiming); } +static boolean P_SpectatorJoinGame(player_t *player) +{ + if (!G_GametypeHasSpectators() && G_IsSpecialStage(gamemap) && useNightsSS) // Special Stage spectators should NEVER be allowed to rejoin the game + { + if (P_IsLocalPlayer(player)) + CONS_Printf(M_GetText("You cannot enter the game while a special stage is in progress.\n")); + player->powers[pw_flashing] += 2*TICRATE; //to prevent message spam. + } + + else if (!cv_allowteamchange.value) + { + if (P_IsLocalPlayer(player)) + CONS_Printf(M_GetText("Server does not allow team change.\n")); + player->powers[pw_flashing] += 2*TICRATE; //to prevent message spam. + } + + // Team changing in Team Match and CTF + // Pressing fire assigns you to a team that needs players if allowed. + // Partial code reproduction from p_tick.c autobalance code. + else if (G_GametypeHasTeams()) + { + INT32 changeto = 0; + INT32 z, numplayersred = 0, numplayersblue = 0; + + //find a team by num players, score, or random if all else fails. + for (z = 0; z < MAXPLAYERS; ++z) + if (playeringame[z]) + { + if (players[z].ctfteam == 1) + ++numplayersred; + else if (players[z].ctfteam == 2) + ++numplayersblue; + } + // for z + + if (numplayersblue > numplayersred) + changeto = 1; + else if (numplayersred > numplayersblue) + changeto = 2; + else if (bluescore > redscore) + changeto = 1; + else if (redscore > bluescore) + changeto = 2; + else + changeto = (P_Random() & 1) + 1; + + if (player->mo) + { + P_RemoveMobj(player->mo); + player->mo = NULL; + } + player->spectator = false; + player->ctfteam = changeto; + player->playerstate = PST_REBORN; + + //Reset away view + if (P_IsLocalPlayer(player) && displayplayer != consoleplayer) + displayplayer = consoleplayer; + + if (changeto == 1) + CONS_Printf(M_GetText("%s switched to the %c%s%c.\n"), player_names[player-players], '\x85', M_GetText("Red Team"), '\x80'); + else if (changeto == 2) + CONS_Printf(M_GetText("%s switched to the %c%s%c.\n"), player_names[player-players], '\x84', M_GetText("Blue Team"), '\x80'); + + return true; // no more player->mo, cannot continue. + } + // Joining in game from firing. + else + { + // Exception for hide and seek. Don't join a game when you simply + // respawn in place and sit there for the rest of the round. + if (!(gametype == GT_HIDEANDSEEK && leveltime > (hidetime * TICRATE))) + { + if (player->mo) + { + P_RemoveMobj(player->mo); + player->mo = NULL; + } + player->spectator = false; + player->playerstate = PST_REBORN; + + if (gametype == GT_TAG) + { + //Make joining players "it" after hidetime. + if (leveltime > (hidetime * TICRATE)) + { + CONS_Printf(M_GetText("%s is now IT!\n"), player_names[player-players]); // Tell everyone who is it! + player->pflags |= PF_TAGIT; + } + + P_CheckSurvivors(); + } + + //Reset away view + if (P_IsLocalPlayer(player) && displayplayer != consoleplayer) + displayplayer = consoleplayer; + + CONS_Printf(M_GetText("%s entered the game.\n"), player_names[player-players]); + return true; // no more player->mo, cannot continue. + } + else + { + if (P_IsLocalPlayer(player)) + CONS_Printf(M_GetText("You must wait until next round to enter the game.\n")); + player->powers[pw_flashing] += 2*TICRATE; //to prevent message spam. + } + } + return false; +} + static void P_CalcPostImg(player_t *player) { sector_t *sector = player->mo->subsector->sector; postimg_t *type; INT32 *param; + fixed_t pviewheight; + + if (player->mo->eflags & MFE_VERTICALFLIP) + pviewheight = player->mo->z + player->mo->height - player->viewheight; + else + pviewheight = player->mo->z + player->viewheight; + + if (player->awayviewtics) + { + sector = player->awayviewmobj->subsector->sector; + pviewheight = player->awayviewmobj->z + 20*FRACUNIT; + } if (splitscreen && player == &players[secondarydisplayplayer]) { @@ -8476,30 +8325,11 @@ static void P_CalcPostImg(player_t *player) if (!(rover->flags & FF_EXISTS)) continue; - if (player->mo->eflags & MFE_VERTICALFLIP) - { - if (*rover->topheight < player->mo->z + player->mo->height - player->viewheight - || *rover->bottomheight >= player->mo->z + player->mo->height - player->viewheight) - continue; + if (pviewheight >= *rover->topheight || pviewheight <= *rover->bottomheight) + continue; - if (player->mo->z + player->mo->height - player->viewheight < *rover->topheight) - { - if (P_FindSpecialLineFromTag(13, rover->master->frontsector->tag, -1) != -1) - *type = postimg_heat; - } - } - else - { - if (*rover->topheight <= player->mo->z + player->viewheight - || *rover->bottomheight > player->mo->z + player->viewheight) - continue; - - if (player->mo->z + player->viewheight < *rover->topheight) - { - if (P_FindSpecialLineFromTag(13, rover->master->frontsector->tag, -1) != -1) - *type = postimg_heat; - } - } + if (P_FindSpecialLineFromTag(13, rover->master->frontsector->tag, -1) != -1) + *type = postimg_heat; } } @@ -8513,24 +8343,10 @@ static void P_CalcPostImg(player_t *player) if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE) || rover->flags & FF_BLOCKPLAYER) continue; - if (player->mo->eflags & MFE_VERTICALFLIP) - { - if (*rover->topheight < player->mo->z + player->mo->height - player->viewheight - || *rover->bottomheight >= player->mo->z + player->mo->height - player->viewheight) - continue; + if (pviewheight >= *rover->topheight || pviewheight <= *rover->bottomheight) + continue; - if (player->mo->z + player->mo->height - player->viewheight > *rover->bottomheight) - *type = postimg_water; - } - else - { - if (*rover->topheight <= player->mo->z + player->viewheight - || *rover->bottomheight > player->mo->z + player->viewheight) - continue; - - if (player->mo->z + player->viewheight < *rover->topheight) - *type = postimg_water; - } + *type = postimg_water; } } @@ -8808,6 +8624,52 @@ void P_PlayerThink(player_t *player) player->realtime = leveltime; } + if ((netgame || splitscreen) && player->spectator && cmd->buttons & BT_ATTACK && !player->powers[pw_flashing]) + { + if (P_SpectatorJoinGame(player)) + return; // player->mo was removed. + } + + // Even if not NiGHTS, pull in nearby objects when walking around as John Q. Elliot. + if (!objectplacing && !((netgame || multiplayer) && player->spectator) + && maptol & TOL_NIGHTS && (!(player->pflags & PF_NIGHTSMODE) || player->powers[pw_nights_helper])) + { + thinker_t *th; + mobj_t *mo2; + fixed_t x = player->mo->x; + fixed_t y = player->mo->y; + fixed_t z = player->mo->z; + + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + mo2 = (mobj_t *)th; + + if (!(mo2->type == MT_NIGHTSWING || mo2->type == MT_RING || mo2->type == MT_COIN +#ifdef BLUE_SPHERES + || mo2->type == MT_BLUEBALL +#endif + )) + continue; + + if (P_AproxDistance(P_AproxDistance(mo2->x - x, mo2->y - y), mo2->z - z) > FixedMul(128*FRACUNIT, player->mo->scale)) + continue; + + // Yay! The thing's in reach! Pull it in! + mo2->flags |= MF_NOCLIP|MF_NOCLIPHEIGHT; + mo2->flags2 |= MF2_NIGHTSPULL; + P_SetTarget(&mo2->tracer, player->mo); + } + } + + if (player->linktimer && !player->powers[pw_nights_linkfreeze]) + { + if (--player->linktimer <= 0) // Link timer + player->linkcount = 0; + } + // Move around. // Reactiontime is used to prevent movement // for a bit after a teleport. @@ -8817,11 +8679,8 @@ void P_PlayerThink(player_t *player) { if (player->pflags & PF_ROPEHANG) { - if ((netgame || (player == &players[consoleplayer] - && !cv_analog.value) || (player == &players[secondarydisplayplayer] && !cv_analog2.value))) - { + if (!P_AnalogMove(player)) player->mo->angle = (cmd->angleturn<<16 /* not FRACBITS */); - } ticruned++; if ((cmd->angleturn & TICCMD_RECEIVED) == 0) @@ -8838,14 +8697,7 @@ void P_PlayerThink(player_t *player) P_SetPlayerMobjState(player->mo, S_PLAY_ATK1); } player->rmomx = player->rmomy = 0; // no actual momentum from your controls - - P_DoSuperStuff(player); - P_CheckSneakerAndLivesTimer(player); - P_DoBubbleBreath(player); - P_CheckUnderwaterAndSpaceTimer(player); - P_CheckInvincibilityTimer(player); P_ResetScore(player); - P_DoPlayerHeadSigns(player); } else P_MovePlayer(player); @@ -8853,6 +8705,35 @@ void P_PlayerThink(player_t *player) if (!player->mo) return; // P_MovePlayer removed player->mo. + P_DoSuperStuff(player); + P_CheckSneakerAndLivesTimer(player); + P_DoBubbleBreath(player); // Spawn Sonic's bubbles + P_CheckUnderwaterAndSpaceTimer(player); // Display the countdown drown numbers! + P_CheckInvincibilityTimer(player); // Spawn Invincibility Sparkles + P_DoPlayerHeadSigns(player); // Spawn Tag/CTF signs over player's head + +#if 1 + // "Blur" a bit when you have speed shoes and are going fast enough + if ((player->powers[pw_super] || player->powers[pw_sneakers]) && (player->speed + abs(player->mo->momz)) > FixedMul(20*FRACUNIT,player->mo->scale)) + { + mobj_t *gmobj = P_SpawnGhostMobj(player->mo); + gmobj->fuse = 2; + if (leveltime & 1) + { + gmobj->frame &= ~FF_TRANSMASK; + gmobj->frame |= tr_trans70<flags2 |= MF2_DONTDRAW; + } +#endif + // check for use if (!(player->pflags & PF_NIGHTSMODE)) { @@ -8869,7 +8750,10 @@ void P_PlayerThink(player_t *player) P_UnsetThingPosition(player->mo->tracer); player->mo->tracer->x = player->mo->x; player->mo->tracer->y = player->mo->y; - player->mo->tracer->z = player->mo->z; + if (player->mo->eflags & MFE_VERTICALFLIP) + player->mo->tracer->z = player->mo->z + player->mo->height - player->mo->tracer->height; + else + player->mo->tracer->z = player->mo->z; player->mo->tracer->floorz = player->mo->floorz; player->mo->tracer->ceilingz = player->mo->ceilingz; P_SetThingPosition(player->mo->tracer); @@ -8891,7 +8775,7 @@ void P_PlayerThink(player_t *player) if (player->powers[pw_tailsfly] && player->powers[pw_tailsfly] < UINT16_MAX && player->charability != CA_SWIM && !(player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds]))) // tails fly counter player->powers[pw_tailsfly]--; - if (player->powers[pw_underwater] && ((player->pflags & PF_GODMODE) || (player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL)) + if (player->powers[pw_underwater] && (player->pflags & PF_GODMODE || (player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL)) { if (player->powers[pw_underwater] <= 12*TICRATE+1) P_RestoreMusic(player); //incase they were about to drown @@ -8901,7 +8785,7 @@ void P_PlayerThink(player_t *player) else if (player->powers[pw_underwater] && !(maptol & TOL_NIGHTS) && !((netgame || multiplayer) && player->spectator)) // underwater timer player->powers[pw_underwater]--; - if (player->powers[pw_spacetime] && ((player->pflags & PF_GODMODE) || (player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL)) + if (player->powers[pw_spacetime] && (player->pflags & PF_GODMODE || (player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL)) player->powers[pw_spacetime] = 0; else if (player->powers[pw_spacetime] && !(maptol & TOL_NIGHTS) && !((netgame || multiplayer) && player->spectator)) // underwater timer player->powers[pw_spacetime]--; @@ -8977,7 +8861,7 @@ void P_PlayerThink(player_t *player) else player->mo->flags2 &= ~MF2_DONTDRAW; } - else + else if (player->mo->tracer) { if (player->powers[pw_flashing] & 1) player->mo->tracer->flags2 |= MF2_DONTDRAW; @@ -9065,7 +8949,7 @@ void P_PlayerAfterThink(player_t *player) if (player->pflags & PF_NIGHTSMODE) { player->powers[pw_gravityboots] = 0; - player->mo->eflags &= ~MFE_VERTICALFLIP; + //player->mo->eflags &= ~MFE_VERTICALFLIP; } if (!(player->pflags & PF_WPNDOWN)) diff --git a/src/r_data.c b/src/r_data.c index c8226b3f1..930b70bf5 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -999,7 +999,7 @@ void R_ReInitColormaps(UINT16 num) char colormap[9] = "COLORMAP"; lumpnum_t lump; - if (num <= 9999) + if (num > 0 && num <= 10000) snprintf(colormap, 8, "CLM%04u", num-1); // Load in the light tables, now 64k aligned for smokie... diff --git a/src/r_defs.h b/src/r_defs.h index f818ed65c..5a5eaf97a 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -155,8 +155,6 @@ typedef struct ffloor_s fixed_t *bottomyoffs; angle_t *bottomangle; - fixed_t delta; - size_t secnum; ffloortype_e flags; struct line_s *master; @@ -269,6 +267,7 @@ typedef struct sector_s angle_t ceilingpic_angle; INT32 heightsec; // other sector, or -1 if no other sector + INT32 camsec; // used for camera clipping INT32 floorlightsec, ceilinglightsec; INT32 crumblestate; // used for crumbling and bobbing diff --git a/src/r_main.c b/src/r_main.c index e17f749e4..231dfe29b 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1304,6 +1304,7 @@ void R_RegisterEngineStuff(void) CV_RegisterVar(&cv_grdynamiclighting); CV_RegisterVar(&cv_grcoronas); CV_RegisterVar(&cv_grcoronasize); + CV_RegisterVar(&cv_grmd2); #endif #ifdef HWRENDER diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj index 958cd7d02..7e25b5ad9 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj +++ b/src/sdl/Srb2SDL-vc10.vcxproj @@ -74,14 +74,14 @@ .\..\..\bin\VC10\$(Platform)\$(Configuration)\ .\..\..\objs\VC10\$(Platform)\$(Configuration)\SDL\ false - $(SDL12_PREFIX)\include;$(SDL12_MIXER_PREFIX)\include;$(FMOD3_PREFIX)api\inc;$(IncludePath) - $(SDL12_PREFIX)\include;$(SDL12_MIXER_PREFIX)\include;$(FMOD3_PREFIX)api\inc;$(IncludePath) - $(SDL12_PREFIX)\include;$(SDL12_MIXER_PREFIX)\include;$(FMOD3_PREFIX)api\inc;$(IncludePath) - $(SDL12_PREFIX)\include;$(SDL12_MIXER_PREFIX)\include;$(FMOD3_PREFIX)api\inc;$(IncludePath) - $(SDL12_PREFIX)\lib;$(SDL12_MIXER_PREFIX)\lib;$(LibraryPath) - $(SDL12_PREFIX)\lib;$(SDL12_MIXER_PREFIX)\lib;$(LibraryPath) - $(SDL12_PREFIX)\lib\x64;$(SDL12_MIXER_PREFIX)\lib\x64;$(LibraryPath) - $(SDL12_PREFIX)\lib\x64;$(SDL12_MIXER_PREFIX)\lib\x64;$(LibraryPath) + $(SDL20_PREFIX)\include;$(SDL20_MIXER_PREFIX)\include;$(FMOD3_PREFIX)api\inc;$(IncludePath) + $(SDL20_PREFIX)\include;$(SDL20_MIXER_PREFIX)\include;$(FMOD3_PREFIX)api\inc;$(IncludePath) + $(SDL20_PREFIX)\include;$(SDL20_MIXER_PREFIX)\include;$(FMOD3_PREFIX)api\inc;$(IncludePath) + $(SDL20_PREFIX)\include;$(SDL20_MIXER_PREFIX)\include;$(FMOD3_PREFIX)api\inc;$(IncludePath) + $(SDL20_PREFIX)\lib;$(SDL20_MIXER_PREFIX)\lib;$(LibraryPath) + $(SDL20_PREFIX)\lib;$(SDL20_MIXER_PREFIX)\lib;$(LibraryPath) + $(SDL20_PREFIX)\lib\x64;$(SDL20_MIXER_PREFIX)\lib\x64;$(LibraryPath) + $(SDL20_PREFIX)\lib\x64;$(SDL20_MIXER_PREFIX)\lib\x64;$(LibraryPath) diff --git a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj index 5c34c55c5..b2d687e24 100644 --- a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj +++ b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj @@ -1214,7 +1214,7 @@ C01FCF4B08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CURRENT_PROJECT_VERSION = 2.1.8; + CURRENT_PROJECT_VERSION = 2.1.9; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", NORMALSRB2, @@ -1226,7 +1226,7 @@ C01FCF4C08A954540054247B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CURRENT_PROJECT_VERSION = 2.1.8; + CURRENT_PROJECT_VERSION = 2.1.9; GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_PREPROCESSOR_DEFINITIONS = ( diff --git a/src/sdl12/Makefile.cfg b/src/sdl12/Makefile.cfg index 1f9c7204f..1d404c4c9 100644 --- a/src/sdl12/Makefile.cfg +++ b/src/sdl12/Makefile.cfg @@ -67,7 +67,7 @@ endif OBJS+=$(OBJDIR)/i_video.o $(OBJDIR)/dosstr.o $(OBJDIR)/endtxt.o $(OBJDIR)/hwsym_sdl.o - OPTS+=-DDIRECTFULLSCREEN -DSDL + OPTS+=-DDIRECTFULLSCREEN -DHAVE_SDL ifndef NOHW OBJS+=$(OBJDIR)/r_opengl.o $(OBJDIR)/ogl_sdl.o diff --git a/src/sdl12/Srb2SDL-vc10.vcxproj b/src/sdl12/Srb2SDL-vc10.vcxproj index 192f19156..958cd7d02 100644 --- a/src/sdl12/Srb2SDL-vc10.vcxproj +++ b/src/sdl12/Srb2SDL-vc10.vcxproj @@ -96,7 +96,7 @@ Disabled $(ProjectDir)..\..\libs\libpng-src;$(ProjectDir)..\..\libs\zlib;%(AdditionalIncludeDirectories) - _DEBUG;USE_WGL_SWAP;DIRECTFULLSCREEN;SDL;HWRENDER;HW3SOUND;HAVE_FILTER;HAVE_MIXER;USEASM;HAVE_PNG;COMPVERSION;HAVE_BLUA;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + _DEBUG;USE_WGL_SWAP;DIRECTFULLSCREEN;HAVE_SDL;HWRENDER;HW3SOUND;HAVE_FILTER;HAVE_MIXER;USEASM;HAVE_PNG;COMPVERSION;HAVE_BLUA;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug @@ -145,7 +145,7 @@ Disabled $(ProjectDir)..\..\libs\libpng-src;$(ProjectDir)..\..\libs\zlib;%(AdditionalIncludeDirectories) - _DEBUG;USE_WGL_SWAP;DIRECTFULLSCREEN;SDL;HWRENDER;HW3SOUND;HAVE_FILTER;HAVE_MIXER;HAVE_PNG;COMPVERSION;HAVE_BLUA;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + _DEBUG;USE_WGL_SWAP;DIRECTFULLSCREEN;HAVE_SDL;HWRENDER;HW3SOUND;HAVE_FILTER;HAVE_MIXER;HAVE_PNG;COMPVERSION;HAVE_BLUA;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebug @@ -202,7 +202,7 @@ Speed true $(ProjectDir)..\..\libs\libpng-src;$(ProjectDir)..\..\libs\zlib;%(AdditionalIncludeDirectories) - NDEBUG;SDLMAIN;NO_STDIO_REDIRECT;USE_WGL_SWAP;DIRECTFULLSCREEN;SDL;HWRENDER;HW3SOUND;HAVE_FILTER;HAVE_MIXER;USEASM;HAVE_PNG;COMPVERSION;HAVE_BLUA;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + NDEBUG;SDLMAIN;NO_STDIO_REDIRECT;USE_WGL_SWAP;DIRECTFULLSCREEN;HAVE_SDL;HWRENDER;HW3SOUND;HAVE_FILTER;HAVE_MIXER;USEASM;HAVE_PNG;COMPVERSION;HAVE_BLUA;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) true MultiThreaded .\..\..\objs\VC10\$(Platform)\$(Configuration)\SDL\Srb2SDL-vc9.pch @@ -258,7 +258,7 @@ Speed true $(ProjectDir)..\..\libs\libpng-src;$(ProjectDir)..\..\libs\zlib;%(AdditionalIncludeDirectories) - NDEBUG;SDLMAIN;NO_STDIO_REDIRECT;USE_WGL_SWAP;DIRECTFULLSCREEN;SDL;HWRENDER;HW3SOUND;HAVE_FILTER;HAVE_MIXER;HAVE_PNG;COMPVERSION;HAVE_BLUA;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + NDEBUG;SDLMAIN;NO_STDIO_REDIRECT;USE_WGL_SWAP;DIRECTFULLSCREEN;HAVE_SDL;HWRENDER;HW3SOUND;HAVE_FILTER;HAVE_MIXER;HAVE_PNG;COMPVERSION;HAVE_BLUA;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) true MultiThreaded .\..\..\objs\VC10\$(Platform)\$(Configuration)\SDL\Srb2SDL-vc9.pch @@ -1461,4 +1461,4 @@ - \ No newline at end of file + diff --git a/src/sdl12/Srb2SDL-vc9.vcproj b/src/sdl12/Srb2SDL-vc9.vcproj index 620202bdf..d2a268f8d 100644 --- a/src/sdl12/Srb2SDL-vc9.vcproj +++ b/src/sdl12/Srb2SDL-vc9.vcproj @@ -50,7 +50,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=""$(ProjectDir)..\..\libs\libpng-src";"$(ProjectDir)..\..\libs\zlib"" - PreprocessorDefinitions="_DEBUG;USE_WGL_SWAP;DIRECTFULLSCREEN;SDL;HWRENDER;HW3SOUND;HAVE_FILTER;HAVE_MIXER;USEASM;HAVE_PNG;HAVE_BLUA;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE" + PreprocessorDefinitions="_DEBUG;USE_WGL_SWAP;DIRECTFULLSCREEN;HAVE_SDL;HWRENDER;HW3SOUND;HAVE_FILTER;HAVE_MIXER;USEASM;HAVE_PNG;HAVE_BLUA;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="1" @@ -145,7 +145,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories=""$(ProjectDir)..\..\libs\libpng-src";"$(ProjectDir)..\..\libs\zlib"" - PreprocessorDefinitions="_DEBUG;USE_WGL_SWAP;DIRECTFULLSCREEN;SDL;HWRENDER;HW3SOUND;HAVE_FILTER;HAVE_MIXER;HAVE_PNG;HAVE_BLUA;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE" + PreprocessorDefinitions="_DEBUG;USE_WGL_SWAP;DIRECTFULLSCREEN;HAVE_SDL;HWRENDER;HW3SOUND;HAVE_FILTER;HAVE_MIXER;HAVE_PNG;HAVE_BLUA;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="1" @@ -248,7 +248,7 @@ FavorSizeOrSpeed="1" OmitFramePointers="true" AdditionalIncludeDirectories=""$(ProjectDir)..\..\libs\libpng-src";"$(ProjectDir)..\..\libs\zlib"" - PreprocessorDefinitions="NDEBUG;SDLMAIN;NO_STDIO_REDIRECT;USE_WGL_SWAP;DIRECTFULLSCREEN;SDL;HWRENDER;HW3SOUND;HAVE_FILTER;HAVE_MIXER;USEASM;HAVE_PNG;HAVE_BLUA;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE" + PreprocessorDefinitions="NDEBUG;SDLMAIN;NO_STDIO_REDIRECT;USE_WGL_SWAP;DIRECTFULLSCREEN;HAVE_SDL;HWRENDER;HW3SOUND;HAVE_FILTER;HAVE_MIXER;USEASM;HAVE_PNG;HAVE_BLUA;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE" StringPooling="true" RuntimeLibrary="0" PrecompiledHeaderFile=".\..\..\objs\VC9\$(Platform)\$(Configuration)\SDL\Srb2SDL-vc9.pch" @@ -350,7 +350,7 @@ FavorSizeOrSpeed="1" OmitFramePointers="true" AdditionalIncludeDirectories=""$(ProjectDir)..\..\libs\libpng-src";"$(ProjectDir)..\..\libs\zlib"" - PreprocessorDefinitions="NDEBUG;SDLMAIN;NO_STDIO_REDIRECT;USE_WGL_SWAP;DIRECTFULLSCREEN;SDL;HWRENDER;HW3SOUND;HAVE_FILTER;HAVE_MIXER;HAVE_PNG;HAVE_BLUA;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE" + PreprocessorDefinitions="NDEBUG;SDLMAIN;NO_STDIO_REDIRECT;USE_WGL_SWAP;DIRECTFULLSCREEN;HAVE_SDL;HWRENDER;HW3SOUND;HAVE_FILTER;HAVE_MIXER;HAVE_PNG;HAVE_BLUA;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE" StringPooling="true" RuntimeLibrary="0" PrecompiledHeaderFile=".\..\..\objs\VC9\$(Platform)\$(Configuration)\SDL\Srb2SDL-vc9.pch" diff --git a/src/sdl12/Srb2SDL.dsp b/src/sdl12/Srb2SDL.dsp index 02c3b2701..879113ca2 100644 --- a/src/sdl12/Srb2SDL.dsp +++ b/src/sdl12/Srb2SDL.dsp @@ -45,7 +45,7 @@ MTL=midl.exe # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /G5 /W3 /GX /Zi /Ot /Og /Oi /Op /Oy /Ob1 /I "..\..\libs\libpng-src" /I "..\..\libs\zlib" /D "NDEBUG" /D "SDLMAIN" /D "NO_STDIO_REDIRECT" /D "USE_WGL_SWAP" /D "DIRECTFULLSCREEN" /D "SDL" /D "HWRENDER" /D "HW3SOUND" /D "HAVE_FILTER" /D "HAVE_MIXER" /D "USEASM" /D "HAVE_PNG" /FR /FD /GF /c +# ADD CPP /nologo /G5 /W3 /GX /Zi /Ot /Og /Oi /Op /Oy /Ob1 /I "..\..\libs\libpng-src" /I "..\..\libs\zlib" /D "NDEBUG" /D "SDLMAIN" /D "NO_STDIO_REDIRECT" /D "USE_WGL_SWAP" /D "DIRECTFULLSCREEN" /D "HAVE_SDL" /D "HWRENDER" /D "HW3SOUND" /D "HAVE_FILTER" /D "HAVE_MIXER" /D "USEASM" /D "HAVE_PNG" /FR /FD /GF /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" # SUBTRACT RSC /x @@ -72,7 +72,7 @@ LINK32=link.exe # PROP Target_Dir "" MTL=midl.exe # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /G6 /W4 /WX /Gm /GX /ZI /Od /Op /I "..\..\libs\libpng-src" /I "..\..\libs\zlib" /D "_DEBUG" /D "USE_WGL_SWAP" /D "DIRECTFULLSCREEN" /D "SDL" /D "HWRENDER" /D "HW3SOUND" /D "HAVE_FILTER" /D "HAVE_MIXER" /D "USEASM" /D "HAVE_PNG" /FR /FD /GZ /c +# ADD CPP /nologo /G6 /W4 /WX /Gm /GX /ZI /Od /Op /I "..\..\libs\libpng-src" /I "..\..\libs\zlib" /D "_DEBUG" /D "USE_WGL_SWAP" /D "DIRECTFULLSCREEN" /D "HAVE_SDL" /D "HWRENDER" /D "HW3SOUND" /D "HAVE_FILTER" /D "HAVE_MIXER" /D "USEASM" /D "HAVE_PNG" /FR /FD /GZ /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" diff --git a/src/sdl12/hwsym_sdl.c b/src/sdl12/hwsym_sdl.c index 43c71f7bf..44ddf830c 100644 --- a/src/sdl12/hwsym_sdl.c +++ b/src/sdl12/hwsym_sdl.c @@ -29,7 +29,7 @@ #pragma warning(disable : 4214 4244) #endif -#ifdef SDL +#ifdef HAVE_SDL #include "SDL.h" diff --git a/src/sdl12/i_cdmus.c b/src/sdl12/i_cdmus.c index adab39c90..1eeac370b 100644 --- a/src/sdl12/i_cdmus.c +++ b/src/sdl12/i_cdmus.c @@ -17,7 +17,7 @@ /// \brief cd music interface /// -#ifdef SDL +#ifdef HAVE_SDL #if defined (DC) || defined (_WIN32_WCE) || defined(GP2X) || defined(_PS3) #define NOSDLCD diff --git a/src/sdl12/i_main.c b/src/sdl12/i_main.c index 85abb7041..1c438e083 100644 --- a/src/sdl12/i_main.c +++ b/src/sdl12/i_main.c @@ -48,7 +48,7 @@ PSP_MAIN_THREAD_NAME("SRB2"); PSP_MAIN_THREAD_STACK_SIZE_KB(256); #endif -#ifdef SDL +#ifdef HAVE_SDL #ifdef HAVE_TTF #include "SDL.h" diff --git a/src/sdl12/i_net.c b/src/sdl12/i_net.c index c31935acf..ee4a34c13 100644 --- a/src/sdl12/i_net.c +++ b/src/sdl12/i_net.c @@ -32,7 +32,7 @@ #include "../i_tcp.h" -#ifdef SDL +#ifdef HAVE_SDL #ifdef HAVE_SDLNET diff --git a/src/sdl12/i_system.c b/src/sdl12/i_system.c index 1e03edd88..888a6a507 100644 --- a/src/sdl12/i_system.c +++ b/src/sdl12/i_system.c @@ -73,7 +73,7 @@ void __set_fpscr(long); // in libgcc / kernel's startup.s? #pragma warning(disable : 4214 4244) #endif -#ifdef SDL +#ifdef HAVE_SDL #include "SDL.h" diff --git a/src/sdl12/i_video.c b/src/sdl12/i_video.c index 1a2305fef..197924eda 100644 --- a/src/sdl12/i_video.c +++ b/src/sdl12/i_video.c @@ -27,7 +27,7 @@ #pragma warning(disable : 4214 4244) #endif -#ifdef SDL +#ifdef HAVE_SDL #include "SDL.h" diff --git a/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj b/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj index 1b1a9fdf6..b2d687e24 100644 --- a/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj +++ b/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj @@ -1214,7 +1214,7 @@ C01FCF4B08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CURRENT_PROJECT_VERSION = 2.1.8; + CURRENT_PROJECT_VERSION = 2.1.9; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", NORMALSRB2, @@ -1226,7 +1226,7 @@ C01FCF4C08A954540054247B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CURRENT_PROJECT_VERSION = 2.1.8; + CURRENT_PROJECT_VERSION = 2.1.9; GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -1264,7 +1264,7 @@ GCC_PREPROCESSOR_DEFINITIONS = ( MAC_ALERT, SDLMAIN, - SDL, + HAVE_SDL, HAVE_MIXER, HAVE_PNG, HAVE_BLUA, @@ -1386,7 +1386,7 @@ GCC_PREPROCESSOR_DEFINITIONS = ( MAC_ALERT, SDLMAIN, - SDL, + HAVE_SDL, HAVE_MIXER, HAVE_PNG, HAVE_BLUA, diff --git a/src/sdl12/mixer_sound.c b/src/sdl12/mixer_sound.c index 98159b473..151668752 100644 --- a/src/sdl12/mixer_sound.c +++ b/src/sdl12/mixer_sound.c @@ -3,7 +3,7 @@ #include "../doomdef.h" -#if defined(SDL) && defined(HAVE_MIXER) && SOUND==SOUND_MIXER +#if defined(HAVE_SDL) && defined(HAVE_MIXER) && SOUND==SOUND_MIXER #include "../sounds.h" #include "../s_sound.h" diff --git a/src/sdl12/ogl_sdl.c b/src/sdl12/ogl_sdl.c index 9427d3317..e726bf07d 100644 --- a/src/sdl12/ogl_sdl.c +++ b/src/sdl12/ogl_sdl.c @@ -21,7 +21,7 @@ #pragma warning(disable : 4214 4244) #endif -#ifdef SDL +#ifdef HAVE_SDL #include "SDL.h" diff --git a/src/sdl12/sdl_sound.c b/src/sdl12/sdl_sound.c index 3750e6778..6ba83104e 100644 --- a/src/sdl12/sdl_sound.c +++ b/src/sdl12/sdl_sound.c @@ -23,7 +23,7 @@ #pragma warning(disable : 4214 4244) #endif -#if defined(SDL) && SOUND==SOUND_SDL +#if defined(HAVE_SDL) && SOUND==SOUND_SDL #include "SDL.h" @@ -2027,4 +2027,4 @@ static void SDLCALL I_FinishMusic(void) if (Msc_Mutex) SDL_UnlockMutex(Msc_Mutex); } #endif -#endif //SDL +#endif //HAVE_SDL diff --git a/src/sounds.h b/src/sounds.h index ee1e60ba1..c5851a346 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -36,7 +36,6 @@ typedef enum SKSSPNDSH, SKSZOOM, SKSSKID, - SKSRADIO, SKSGASP, SKSJUMP, NUMSKINSOUNDS diff --git a/src/st_stuff.c b/src/st_stuff.c index 4bba8eb52..ae8c2f500 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -759,7 +759,7 @@ static void ST_drawLevelTitle(void) } if (actnum) - V_DrawScaledPatch(SCX(ttlnumxpos), SCZ(zoney), V_NOSCALESTART, ttlnum); + V_DrawScaledPatch(ttlnumxpos, zoney, 0, ttlnum); V_DrawLevelTitle(lvlttlxpos, lvlttly, 0, lvlttl); @@ -1906,6 +1906,8 @@ static void ST_overlayDrawer(void) V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(60), V_HUDTRANSHALF, M_GetText("You are a spectator.")); if (G_GametypeHasTeams()) V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), V_HUDTRANSHALF, M_GetText("Press Fire to be assigned to a team.")); + else if (G_IsSpecialStage(gamemap) && useNightsSS) + V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), V_HUDTRANSHALF, M_GetText("You cannot join the game until the stage has ended.")); else V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), V_HUDTRANSHALF, M_GetText("Press Fire to enter the game.")); V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(148), V_HUDTRANSHALF, M_GetText("Press F12 to watch another player.")); diff --git a/src/v_video.c b/src/v_video.c index d6ab2eef1..52fefe4c6 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -75,6 +75,10 @@ consvar_t cv_grdynamiclighting = {"gr_dynamiclighting", "On", CV_SAVE, CV_OnOff, consvar_t cv_grstaticlighting = {"gr_staticlighting", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_grcoronas = {"gr_coronas", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_grcoronasize = {"gr_coronasize", "1", CV_SAVE| CV_FLOAT, 0, NULL, 0, NULL, NULL, 0, 0, NULL}; + +static CV_PossibleValue_t CV_MD2[] = {{0, "Off"}, {1, "On"}, {2, "Old"}, {0, NULL}}; +// console variables in development +consvar_t cv_grmd2 = {"gr_md2", "Off", CV_SAVE, CV_MD2, NULL, 0, NULL, NULL, 0, 0, NULL}; #endif const UINT8 gammatable[5][256] = @@ -191,7 +195,7 @@ const char *R_GetPalname(UINT16 num) static char palname[9]; char newpal[9] = "PLAYPAL"; - if (num <= 9999) + if (num > 0 && num <= 10000) snprintf(newpal, 8, "PAL%04u", num-1); strncpy(palname, newpal, 8); @@ -926,11 +930,9 @@ void V_DrawPatchFill(patch_t *pat) // void V_DrawFadeScreen(void) { - INT32 x, y, w; - INT32 *buf; - UINT32 quad; - UINT8 p1, p2, p3, p4; - const UINT8 *fadetable = (UINT8 *)colormaps + 16*256, *deststop = screens[0] + vid.rowbytes * vid.height; + const UINT8 *fadetable = (UINT8 *)colormaps + 16*256; + const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height; + UINT8 *buf = screens[0]; #ifdef HWRENDER if (rendermode != render_soft && rendermode != render_none) @@ -940,133 +942,52 @@ void V_DrawFadeScreen(void) } #endif - w = vid.width>>2; - for (y = 0; y < vid.height; y++) - { - buf = (INT32 *)(void *)(screens[0] + vid.width*y); - for (x = 0; x < w; x++) - { - if (buf+ x > (const INT32 *)(const void *)deststop) - return; - M_Memcpy(&quad,buf+x,sizeof (quad)); //quad = buf[x]; - p1 = fadetable[quad&255]; - p2 = fadetable[(quad>>8)&255]; - p3 = fadetable[(quad>>16)&255]; - p4 = fadetable[quad>>24]; - quad = (p4<<24) | (p3<<16) | (p2<<8) | p1;//buf[x] = (p4<<24) | (p3<<16) | (p2<<8) | p1; - M_Memcpy(buf+x,&quad,sizeof (quad)); - } - } + // heavily simplified -- we don't need to know x or y + // position when we're doing a full screen fade + for (; buf < deststop; ++buf) + *buf = fadetable[*buf]; } -// Simple translucency with one color. Coords are resolution dependent. -// -void V_DrawFadeConsBack(INT32 px1, INT32 py1, INT32 px2, INT32 py2, INT32 color) +// Simple translucency with one color, over a set number of lines starting from the top. +void V_DrawFadeConsBack(INT32 plines, INT32 pcolor) { - INT32 x, y, w; - INT32 *buf; - UINT32 quad; - UINT8 p1, p2, p3, p4; - INT16 *wput; - const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height; - UINT8 *colormap; + UINT8 *deststop, *colormap, *buf; #ifdef HWRENDER // not win32 only 19990829 by Kin if (rendermode != render_soft && rendermode != render_none) { UINT32 hwcolor; - - switch (color) + switch (pcolor) { - case 0: // white - hwcolor = 0xffffff00; - break; - case 1: // orange - hwcolor = 0xff800000; - break; - case 2: // blue - hwcolor = 0x0000ff00; - break; - case 3: // green - hwcolor = 0x00800000; - break; - case 4: // gray - hwcolor = 0x80808000; - break; - case 5: // red - hwcolor = 0xff000000; - break; - default: - hwcolor = 0x00800000; - break; + case 0: hwcolor = 0xffffff00; break; //white + case 1: hwcolor = 0xff800000; break; //orange + case 2: hwcolor = 0x0000ff00; break; //blue + case 3: hwcolor = 0x00800000; break; //green + case 4: hwcolor = 0x80808000; break; //gray + case 5: hwcolor = 0xff000000; break; //red + default: hwcolor = 0x00800000; break; //green } - - HWR_DrawConsoleBack(hwcolor, py2); + HWR_DrawConsoleBack(hwcolor, plines); return; } #endif - switch (color) + switch (pcolor) { - case 0: - colormap = cwhitemap; - break; - case 1: - colormap = corangemap; - break; - case 2: - colormap = cbluemap; - break; - case 3: - colormap = cgreenmap; - break; - case 4: - colormap = cgraymap; - break; - case 5: - colormap = credmap; - break; - default: - colormap = cgreenmap; - break; + case 0: colormap = cwhitemap; break; + case 1: colormap = corangemap; break; + case 2: colormap = cbluemap; break; + case 3: colormap = cgreenmap; break; + case 4: colormap = cgraymap; break; + case 5: colormap = credmap; break; + default: colormap = cgreenmap; break; } - if (scr_bpp == 1) - { - px1 >>=2; - px2 >>=2; - for (y = py1; y < py2; y++) - { - buf = (INT32 *)(void *)(screens[0] + vid.width*y); - for (x = px1; x < px2; x++) - { - if (&buf[x] > (const INT32 *)(const void *)deststop) - return; - M_Memcpy(&quad,buf+x,sizeof (quad)); //quad = buf[x]; - p1 = colormap[quad&255]; - p2 = colormap[(quad>>8)&255]; - p3 = colormap[(quad>>16)&255]; - p4 = colormap[quad>>24]; - quad = (p4<<24) | (p3<<16) | (p2<<8) | p1;//buf[x] = (p4<<24) | (p3<<16) | (p2<<8) | p1; - M_Memcpy(buf+x, &quad, sizeof (quad)); - } - } - } - else - { - w = px2 - px1; - for (y = py1; y < py2; y++) - { - wput = (INT16 *)(void *)(screens[0] + vid.width*y) + px1; - for (x = 0; x < w; x++) - { - if (wput > (const INT16 *)(const void *)deststop) - return; - *wput = (INT16)(((*wput&0x7bde) + (15<<5)) >>1); - wput++; - } - } - } + // heavily simplified -- we don't need to know x or y position, + // just the stop position + deststop = screens[0] + vid.rowbytes * min(plines, vid.height); + for (buf = screens[0]; buf < deststop; ++buf) + *buf = colormap[*buf]; } // Gets string colormap, used for 0x80 color codes @@ -1392,6 +1313,12 @@ void V_DrawSmallString(INT32 x, INT32 y, INT32 option, const char *string) } } +void V_DrawRightAlignedSmallString(INT32 x, INT32 y, INT32 option, const char *string) +{ + x -= V_SmallStringWidth(string, option); + V_DrawSmallString(x, y, option, string); +} + // // Write a string using the tny_font // NOTE: the text is centered for screens larger than the base width @@ -1824,6 +1751,44 @@ INT32 V_StringWidth(const char *string, INT32 option) return w; } +// +// Find string width from hu_font chars, 0.5x scale +// +INT32 V_SmallStringWidth(const char *string, INT32 option) +{ + INT32 c, w = 0; + INT32 spacewidth = 2, charwidth = 0; + size_t i; + + switch (option & V_SPACINGMASK) + { + case V_MONOSPACE: + spacewidth = 4; + case V_OLDSPACING: + charwidth = 4; + break; + case V_6WIDTHSPACE: + spacewidth = 3; + default: + break; + } + + for (i = 0; i < strlen(string); i++) + { + c = string[i]; + if ((UINT8)c >= 0x80 && (UINT8)c <= 0x89) //color parsing! -Inuyasha 2.16.09 + continue; + + c = toupper(c) - HU_FONTSTART; + if (c < 0 || c >= HU_FONTSIZE || !hu_font[c]) + w += spacewidth; + else + w += (charwidth ? charwidth : SHORT(hu_font[c]->width)/2); + } + + return w; +} + // // Find string width from tny_font chars // @@ -1903,61 +1868,61 @@ void V_DoPostProcessor(INT32 view, postimg_t type, INT32 param) if (type == postimg_water) { - UINT8 *tmpscr = screens[4]; - UINT8 *srcscr = screens[0]; - INT32 y; - angle_t disStart = (leveltime * 128) & FINEMASK; // in 0 to FINEANGLE - INT32 newpix; - INT32 sine; - //UINT8 *transme = ((tr_trans50)<>FRACBITS; + newpix = abs(sine); + + if (sine < 0) { - sine = (FINESINE(disStart)*5)>>FRACBITS; - newpix = abs(sine); + M_Memcpy(&tmpscr[y*vid.width+newpix], &srcscr[y*vid.width], vid.width-newpix); - if (sine < 0) + // Cleanup edge + while (newpix) { - M_Memcpy(&tmpscr[y*vid.width+newpix], &srcscr[y*vid.width], vid.width-newpix); - - // Cleanup edge - while (newpix) - { - tmpscr[y*vid.width+newpix] = srcscr[y*vid.width]; - newpix--; - } + tmpscr[y*vid.width+newpix] = srcscr[y*vid.width]; + newpix--; } - else + } + else + { + M_Memcpy(&tmpscr[y*vid.width+0], &srcscr[y*vid.width+sine], vid.width-newpix); + + // Cleanup edge + while (newpix) { - M_Memcpy(&tmpscr[y*vid.width+0], &srcscr[y*vid.width+sine], vid.width-newpix); - - // Cleanup edge - while (newpix) - { - tmpscr[y*vid.width+vid.width-newpix] = srcscr[y*vid.width+(vid.width-1)]; - newpix--; - } + tmpscr[y*vid.width+vid.width-newpix] = srcscr[y*vid.width+(vid.width-1)]; + newpix--; } + } /* Unoptimized version - for (x = 0; x < vid.width*vid.bpp; x++) - { - newpix = (x + sine); + for (x = 0; x < vid.width*vid.bpp; x++) + { + newpix = (x + sine); - if (newpix < 0) - newpix = 0; - else if (newpix >= vid.width) - newpix = vid.width-1; + if (newpix < 0) + newpix = 0; + else if (newpix >= vid.width) + newpix = vid.width-1; - tmpscr[y*vid.width + x] = srcscr[y*vid.width+newpix]; // *(transme + (srcscr[y*vid.width+x]<<8) + srcscr[y*vid.width+newpix]); - }*/ - disStart += 22;//the offset into the displacement map, increment each game loop - disStart &= FINEMASK; //clip it to FINEMASK - } + tmpscr[y*vid.width + x] = srcscr[y*vid.width+newpix]; // *(transme + (srcscr[y*vid.width+x]<<8) + srcscr[y*vid.width+newpix]); + }*/ + disStart += 22;//the offset into the displacement map, increment each game loop + disStart &= FINEMASK; //clip it to FINEMASK + } - VID_BlitLinearScreen(tmpscr+vid.width*vid.bpp*yoffset, screens[0]+vid.width*vid.bpp*yoffset, - vid.width*vid.bpp, height, vid.width*vid.bpp, vid.width); + VID_BlitLinearScreen(tmpscr+vid.width*vid.bpp*yoffset, screens[0]+vid.width*vid.bpp*yoffset, + vid.width*vid.bpp, height, vid.width*vid.bpp, vid.width); } else if (type == postimg_motion) // Motion Blur! { diff --git a/src/v_video.h b/src/v_video.h index 4e08e7004..85dbc3884 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -145,7 +145,7 @@ void V_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatnum); // fade down the screen buffer before drawing the menu over void V_DrawFadeScreen(void); -void V_DrawFadeConsBack(INT32 px1, INT32 py1, INT32 px2, INT32 py2, INT32 pcolor); +void V_DrawFadeConsBack(INT32 plines, INT32 pcolor); // draw a single character void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed); @@ -160,8 +160,11 @@ void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string); void V_DrawCenteredString(INT32 x, INT32 y, INT32 option, const char *string); void V_DrawRightAlignedString(INT32 x, INT32 y, INT32 option, const char *string); +// draw a string using the hu_font, 0.5x scale void V_DrawSmallString(INT32 x, INT32 y, INT32 option, const char *string); +void V_DrawRightAlignedSmallString(INT32 x, INT32 y, INT32 option, const char *string); +// draw a string using the tny_font void V_DrawThinString(INT32 x, INT32 y, INT32 option, const char *string); void V_DrawRightAlignedThinString(INT32 x, INT32 y, INT32 option, const char *string); @@ -180,6 +183,8 @@ INT32 V_CreditStringWidth(const char *string); // Find string width from hu_font chars INT32 V_StringWidth(const char *string, INT32 option); +// Find string width from hu_font chars, 0.5x scale +INT32 V_SmallStringWidth(const char *string, INT32 option); // Find string width from tny_font chars INT32 V_ThinStringWidth(const char *string, INT32 option);