From 3e06fa6fc52c0ea56ee65b81e1abe2a90191f75b Mon Sep 17 00:00:00 2001 From: Bitl Date: Fri, 14 Dec 2018 10:59:16 -0700 Subject: [PATCH] Added a new mod called the Revenge Mod. --- Build/Data/Highscore | 2 + Build/Data/HighscoreRevenge | 2 + Build/Enhanced-Changes.txt | 3 + Build/blackshades_revenge.exe | Bin 0 -> 348160 bytes Build/config.txt | 30 + README.md | 7 +- blackshades_revenge/BlackShades.mcp | Bin 0 -> 87343 bytes blackshades_revenge/BlackShades.rsrc | 0 .../IF_THIS_IS_A_README_YOU_HAVE_WON | 30 + blackshades_revenge/Makefile | 84 + blackshades_revenge/Makefile.zakk | 77 + blackshades_revenge/Readme | 117 + blackshades_revenge/Readme.html | 138 + blackshades_revenge/Source/AGL_DSp.cpp | 242 + blackshades_revenge/Source/AGL_DSp.h | 41 + blackshades_revenge/Source/Alerts.cpp | 93 + blackshades_revenge/Source/Alerts.h | 44 + blackshades_revenge/Source/Camera.cpp | 9 + blackshades_revenge/Source/Camera.h | 33 + blackshades_revenge/Source/Constants.h | 173 + blackshades_revenge/Source/Decals.cpp | 449 ++ blackshades_revenge/Source/Decals.h | 63 + blackshades_revenge/Source/Files.cpp | 197 + blackshades_revenge/Source/Files.h | 123 + blackshades_revenge/Source/Fog.cpp | 54 + blackshades_revenge/Source/Fog.h | 33 + blackshades_revenge/Source/Frustum.cpp | 249 + blackshades_revenge/Source/Frustum.h | 14 + blackshades_revenge/Source/Game.h | 255 + blackshades_revenge/Source/GameDraw.cpp | 1772 ++++++ .../Source/GameInitDispose.cpp | 3929 +++++++++++++ blackshades_revenge/Source/GameLoop.cpp | 558 ++ blackshades_revenge/Source/GameTick.cpp | 5061 +++++++++++++++++ blackshades_revenge/Source/Globals.cpp | 90 + blackshades_revenge/Source/MacInput.cpp | 65 + blackshades_revenge/Source/MacInput.h | 112 + blackshades_revenge/Source/Main.cpp | 40 + blackshades_revenge/Source/Maths.cpp | 24 + blackshades_revenge/Source/Maths.h | 11 + blackshades_revenge/Source/Models.cpp | 341 ++ blackshades_revenge/Source/Models.h | 70 + blackshades_revenge/Source/Person.cpp | 1076 ++++ blackshades_revenge/Source/Person.h | 166 + blackshades_revenge/Source/PhysicsMath.h | 1432 +++++ blackshades_revenge/Source/Quaternions.cpp | 752 +++ blackshades_revenge/Source/Quaternions.h | 98 + blackshades_revenge/Source/Serialize.cpp | 114 + blackshades_revenge/Source/Serialize.h | 13 + blackshades_revenge/Source/Skeleton.cpp | 866 +++ blackshades_revenge/Source/Skeleton.h | 173 + blackshades_revenge/Source/SoundFX.cpp | 3 + blackshades_revenge/Source/SoundFX.h | 239 + blackshades_revenge/Source/Sprites.cpp | 505 ++ blackshades_revenge/Source/Sprites.h | 99 + blackshades_revenge/Source/Support.cpp | 411 ++ blackshades_revenge/Source/Support.h | 80 + blackshades_revenge/Source/TGALoader.cpp | 87 + blackshades_revenge/Source/TGALoader.h | 38 + blackshades_revenge/Source/Text.cpp | 92 + blackshades_revenge/Source/Text.h | 37 + blackshades_revenge/Source/Timer.cpp | 31 + blackshades_revenge/Source/Timer.h | 18 + blackshades_revenge/Source/macdefines.h | 7 + blackshades_revenge/TODO | 32 + blackshades_revenge/blackshades.dsp | 297 + blackshades_revenge/blackshades.plg | 48 + blackshades_revenge/blackshades.rc | 72 + blackshades_revenge/blackshades_revenge.dsw | 29 + blackshades_revenge/blackshades_revenge.ncb | Bin 0 -> 271360 bytes blackshades_revenge/blackshades_revenge.opt | Bin 0 -> 51712 bytes blackshades_revenge/icon.tga | Bin 0 -> 6339 bytes blackshades_revenge/notes.txt | 85 + blackshades_revenge/res/Thumbs.db | Bin 0 -> 3072 bytes blackshades_revenge/res/bs.ico | Bin 0 -> 25214 bytes blackshades_revenge/resource.h | 16 + blackshades_revenge/stderr.txt | 1 + blackshades_revenge/uDevGame_License | 1 + blackshades_revenge/uDevGame_License.txt | 54 + blackshades_revenge/uDevGame_Readme | 13 + images/revengeimage1.png | Bin 0 -> 77717 bytes 80 files changed, 21618 insertions(+), 2 deletions(-) create mode 100644 Build/Data/Highscore create mode 100644 Build/Data/HighscoreRevenge create mode 100644 Build/blackshades_revenge.exe create mode 100644 Build/config.txt create mode 100644 blackshades_revenge/BlackShades.mcp create mode 100644 blackshades_revenge/BlackShades.rsrc create mode 100644 blackshades_revenge/IF_THIS_IS_A_README_YOU_HAVE_WON create mode 100644 blackshades_revenge/Makefile create mode 100644 blackshades_revenge/Makefile.zakk create mode 100644 blackshades_revenge/Readme create mode 100644 blackshades_revenge/Readme.html create mode 100644 blackshades_revenge/Source/AGL_DSp.cpp create mode 100644 blackshades_revenge/Source/AGL_DSp.h create mode 100644 blackshades_revenge/Source/Alerts.cpp create mode 100644 blackshades_revenge/Source/Alerts.h create mode 100644 blackshades_revenge/Source/Camera.cpp create mode 100644 blackshades_revenge/Source/Camera.h create mode 100644 blackshades_revenge/Source/Constants.h create mode 100644 blackshades_revenge/Source/Decals.cpp create mode 100644 blackshades_revenge/Source/Decals.h create mode 100644 blackshades_revenge/Source/Files.cpp create mode 100644 blackshades_revenge/Source/Files.h create mode 100644 blackshades_revenge/Source/Fog.cpp create mode 100644 blackshades_revenge/Source/Fog.h create mode 100644 blackshades_revenge/Source/Frustum.cpp create mode 100644 blackshades_revenge/Source/Frustum.h create mode 100644 blackshades_revenge/Source/Game.h create mode 100644 blackshades_revenge/Source/GameDraw.cpp create mode 100644 blackshades_revenge/Source/GameInitDispose.cpp create mode 100644 blackshades_revenge/Source/GameLoop.cpp create mode 100644 blackshades_revenge/Source/GameTick.cpp create mode 100644 blackshades_revenge/Source/Globals.cpp create mode 100644 blackshades_revenge/Source/MacInput.cpp create mode 100644 blackshades_revenge/Source/MacInput.h create mode 100644 blackshades_revenge/Source/Main.cpp create mode 100644 blackshades_revenge/Source/Maths.cpp create mode 100644 blackshades_revenge/Source/Maths.h create mode 100644 blackshades_revenge/Source/Models.cpp create mode 100644 blackshades_revenge/Source/Models.h create mode 100644 blackshades_revenge/Source/Person.cpp create mode 100644 blackshades_revenge/Source/Person.h create mode 100644 blackshades_revenge/Source/PhysicsMath.h create mode 100644 blackshades_revenge/Source/Quaternions.cpp create mode 100644 blackshades_revenge/Source/Quaternions.h create mode 100644 blackshades_revenge/Source/Serialize.cpp create mode 100644 blackshades_revenge/Source/Serialize.h create mode 100644 blackshades_revenge/Source/Skeleton.cpp create mode 100644 blackshades_revenge/Source/Skeleton.h create mode 100644 blackshades_revenge/Source/SoundFX.cpp create mode 100644 blackshades_revenge/Source/SoundFX.h create mode 100644 blackshades_revenge/Source/Sprites.cpp create mode 100644 blackshades_revenge/Source/Sprites.h create mode 100644 blackshades_revenge/Source/Support.cpp create mode 100644 blackshades_revenge/Source/Support.h create mode 100644 blackshades_revenge/Source/TGALoader.cpp create mode 100644 blackshades_revenge/Source/TGALoader.h create mode 100644 blackshades_revenge/Source/Text.cpp create mode 100644 blackshades_revenge/Source/Text.h create mode 100644 blackshades_revenge/Source/Timer.cpp create mode 100644 blackshades_revenge/Source/Timer.h create mode 100644 blackshades_revenge/Source/macdefines.h create mode 100644 blackshades_revenge/TODO create mode 100644 blackshades_revenge/blackshades.dsp create mode 100644 blackshades_revenge/blackshades.plg create mode 100644 blackshades_revenge/blackshades.rc create mode 100644 blackshades_revenge/blackshades_revenge.dsw create mode 100644 blackshades_revenge/blackshades_revenge.ncb create mode 100644 blackshades_revenge/blackshades_revenge.opt create mode 100644 blackshades_revenge/icon.tga create mode 100644 blackshades_revenge/notes.txt create mode 100644 blackshades_revenge/res/Thumbs.db create mode 100644 blackshades_revenge/res/bs.ico create mode 100644 blackshades_revenge/resource.h create mode 100644 blackshades_revenge/stderr.txt create mode 100644 blackshades_revenge/uDevGame_License create mode 100644 blackshades_revenge/uDevGame_License.txt create mode 100644 blackshades_revenge/uDevGame_Readme create mode 100644 images/revengeimage1.png diff --git a/Build/Data/Highscore b/Build/Data/Highscore new file mode 100644 index 0000000..9aea9e0 --- /dev/null +++ b/Build/Data/Highscore @@ -0,0 +1,2 @@ +0 +0 \ No newline at end of file diff --git a/Build/Data/HighscoreRevenge b/Build/Data/HighscoreRevenge new file mode 100644 index 0000000..9aea9e0 --- /dev/null +++ b/Build/Data/HighscoreRevenge @@ -0,0 +1,2 @@ +0 +0 \ No newline at end of file diff --git a/Build/Enhanced-Changes.txt b/Build/Enhanced-Changes.txt index 38b0c28..db6c9d0 100644 --- a/Build/Enhanced-Changes.txt +++ b/Build/Enhanced-Changes.txt @@ -1,3 +1,6 @@ +Black Shades Enhanced v1.1.1R and Black Shades Revenge Mod v1.0 +- Added a seperate gameplay mod called "Revenge Mod", where the player has to defend themselves against assassins. + Black Shades Enhanced v1.1.1 - Fixed an issue where disabling music would make the program hang. diff --git a/Build/blackshades_revenge.exe b/Build/blackshades_revenge.exe new file mode 100644 index 0000000000000000000000000000000000000000..42e6d612e1aff8bc88328c8e0635e98f63f49920 GIT binary patch literal 348160 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 literal 0 HcmV?d00001 diff --git a/Build/config.txt b/Build/config.txt new file mode 100644 index 0000000..aab9702 --- /dev/null +++ b/Build/config.txt @@ -0,0 +1,30 @@ +Screenwidth: +640 +Screenheight: +480 +Mouse sensitivity: +0.7 +Show fps and other info: +0 +VBL sync: +1 +Blood: +1 +Blur: +0 +Main Menu: +1 +Custom levels: +0 +Music: +1 +azerty keyboard: +0 +invert mouse: +0 +Fps (frames per second) limit: +300 +Full Screen: +1 +FOV (Field of View): +90 \ No newline at end of file diff --git a/README.md b/README.md index fdcc6c1..cdd0ee0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Black Shades Enhanced +# Black Shades Enhanced and Revenge Mod Hello everyone. Very recently, I figured out how to compile the code of Black Shades' Windows port, which I documented here: @@ -16,7 +16,7 @@ But recently I figured out a way to compile it, and thus the Black Shades Enhanc **What is included?** -As of v1.1.1: +As of v1.1.1R: - Increased the FPS limit from 90 to 300. - Allows the user to set the FPS limit in the config.txt - Allows the user to run the game in windowed mode. @@ -27,6 +27,7 @@ As of v1.1.1: - Fixed all compiler warnings! - Includes the soundtrack! - Fixed an issue where disabling music would make the program hang. +- A seperate mod called the Revenge mod. Your VIP is gone, so you have to defend yourself against hordes of assassins. All the new settings can be set in the config.txt the game generates. @@ -40,6 +41,8 @@ All the new settings can be set in the config.txt the game generates. ![4](https://github.com/Bitl/Black-Shades-Enhanced/raw/master/images/img4.png) +![RevengeImage1](https://github.com/Bitl/Black-Shades-Enhanced/raw/master/images/revengeimage1.png) + **Credits:** All credits go to Wolfire Games and David for the creation of Black Shades. diff --git a/blackshades_revenge/BlackShades.mcp b/blackshades_revenge/BlackShades.mcp new file mode 100644 index 0000000000000000000000000000000000000000..8ad65505b8e8fb36ece9aa20e372aa88afc66eef GIT binary patch literal 87343 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 literal 0 HcmV?d00001 diff --git a/blackshades_revenge/BlackShades.rsrc b/blackshades_revenge/BlackShades.rsrc new file mode 100644 index 0000000..e69de29 diff --git a/blackshades_revenge/IF_THIS_IS_A_README_YOU_HAVE_WON b/blackshades_revenge/IF_THIS_IS_A_README_YOU_HAVE_WON new file mode 100644 index 0000000..1e276f6 --- /dev/null +++ b/blackshades_revenge/IF_THIS_IS_A_README_YOU_HAVE_WON @@ -0,0 +1,30 @@ +Right now it's all compiling... +http://filesingularity.timedoctor.org/Textures.tar.bz2 +untar that in the Data/ dir to get the targas until somebody adds png support. +See "Readme" for the developer's original, which of course contains notes on playing the game and such. +Additional things we added: +Ctrl+G to grab/ungrab the cursor +ALT+Enter to switch to fullscreen and back again + +Note that you need reasonably new OpenAL libs from +http://opensource.creative.com/ +Most distros which have openal at all, probably won't have the latest and greatest. +For instance I'm told openal in debian unstable is from 2001. +If you don't want to update your OpenAL, you can add -DDEBIAN_NEEDS_TO_UPDATE_THEIR_OPENAL +Complaints about the name of the #define will be nulled ;-) + +If you want fullscreen at startup, currently you have to -DFULLSCREEN. +I don't suggest doing this in OS X however as it seems to have a porblem keeping the mouse properly grabbed, thus requiring some key combination. + +If you're on a platform where you A) Don't have Ogg Vorbis support in your OpenAL, or B) Like to redownload large wav files, be my guest and -DNOOGG and get http://filesingularity.timedoctor.org/Data.tar.bz2 for the wavs + +Ported by: +relnev +theoddone33 +icculus +zakk + +The Bug fixed by: +Toby Haynes + +send diffs to zakk@timedoctor.org diff --git a/blackshades_revenge/Makefile b/blackshades_revenge/Makefile new file mode 100644 index 0000000..55e4658 --- /dev/null +++ b/blackshades_revenge/Makefile @@ -0,0 +1,84 @@ +CC := gcc +CXX := g++ +LINKER := g++ +ASM := nasm +SRCDIR := ./Source +BINDIR := ./objs +EXE := $(BINDIR)/blackshades + +CFLAGS := -O2 -Wall -g $(shell sdl-config --cflags) -I$(SRCDIR) -include Source/Support.h +CXXFLAGS := $(CFLAGS) +LDFLAGS := $(shell sdl-config --libs) -lGL -lGLU -lopenal # -framework QuickTime + +# Don't want ogg? +#CFLAGS += -DNOOGG +# Got ogg? +LDFLAGS += -lvorbisfile -lvorbis + +SRCS := Camera.cpp \ + Decals.cpp \ + Fog.cpp \ + Frustum.cpp \ + GameDraw.cpp \ + GameInitDispose.cpp \ + GameLoop.cpp \ + GameTick.cpp \ + Globals.cpp \ + MacInput.cpp \ + Main.cpp \ + Maths.cpp \ + Models.cpp \ + Person.cpp \ + Quaternions.cpp \ + Serialize.cpp \ + Skeleton.cpp \ + Sprites.cpp \ + Support.cpp \ + TGALoader.cpp \ + Text.cpp \ + Timer.cpp + +OBJS1 := $(SRCS:.c=.o) +OBJS2 := $(OBJS1:.cpp=.o) +OBJS3 := $(OBJS2:.asm=.o) +OBJS := $(foreach f,$(OBJS3),$(BINDIR)/$(f)) +SRCS := $(foreach f,$(SRCS),$(SRCDIR)/$(f)) + +CLEANUP = $(wildcard *.exe) $(wildcard *.obj) \ + $(wildcard $(BINDIR)/*.exe) $(wildcard $(BINDIR)/*.obj) \ + $(wildcard *~) $(wildcard *.err) \ + $(wildcard .\#*) core $(EXE) + + +# Rules for compiling individual source files... + +$(BINDIR)/%.o: $(SRCDIR)/%.cpp + $(CXX) -c -o $@ $< $(CXXFLAGS) + +$(BINDIR)/%.o: $(SRCDIR)/%.c + $(CC) -c -o $@ $< $(CFLAGS) + +$(BINDIR)/%.o: $(SRCDIR)/%.asm + $(ASM) $(ASMFLAGS) -o $@ $< + +.PHONY: all bindir blackshades +all: $(EXE) + +$(EXE): $(BINDIR) $(OBJS) + $(LINKER) -o $(EXE) $(OBJS) $(LDFLAGS) + +$(BINDIR) : + $(MAKE) bindir + +bindir: + mkdir -p $(BINDIR) + +distclean: clean + +clean: + rm -f $(CLEANUP) + rm -rf $(BINDIR) + +# end of Makefile. + + diff --git a/blackshades_revenge/Makefile.zakk b/blackshades_revenge/Makefile.zakk new file mode 100644 index 0000000..f8b1e5d --- /dev/null +++ b/blackshades_revenge/Makefile.zakk @@ -0,0 +1,77 @@ +CC := gcc +CXX := g++ +LINKER := g++ +ASM := nasm +SRCDIR := ./Source +BINDIR := ./objs +EXE := $(BINDIR)/blackshades + +CFLAGS := -g $(shell sdl-config --cflags) -I/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/CarbonSound.framework/Versions/A/Headers -I/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/Headers -I/System/Library/Frameworks/GLUT.framework/Versions/A/Headers -I/System/Library/Frameworks/DrawSprocket.framework/Versions/A/Headers -I/Developer/Headers/FlatCarbon -I/System/Library/Frameworks/AGL.framework/Versions/A/Headers -I/System/Library/Frameworks/OpenGL.framework/Versions/A/Headers -I/sw/include -I/sw/include/AL -I/usr/X11R6/include -D POOLOOPS -I$(SRCDIR) +CXXFLAGS := $(CFLAGS) +LDFLAGS := $(shell sdl-config --libs) -framework QuickTime + +SRCS := Camera.cpp \ + Decals.cpp \ + Files.cpp \ + Fog.cpp \ + Frustum.cpp \ + GameDraw.cpp \ + GameInitDispose.cpp \ + GameLoop.cpp \ + GameTick.cpp \ + Globals.cpp \ + Main.cpp \ + Maths.cpp \ + Models.cpp \ + Person.cpp \ + Quaternions.cpp \ + Skeleton.cpp \ + Sprites.cpp \ + TGALoader.cpp \ + Text.cpp \ + Timer.cpp + +OBJS1 := $(SRCS:.c=.o) +OBJS2 := $(OBJS1:.cpp=.o) +OBJS3 := $(OBJS2:.asm=.o) +OBJS := $(foreach f,$(OBJS3),$(BINDIR)/$(f)) +SRCS := $(foreach f,$(SRCS),$(SRCDIR)/$(f)) + +CLEANUP = $(wildcard *.exe) $(wildcard *.obj) \ + $(wildcard $(BINDIR)/*.exe) $(wildcard $(BINDIR)/*.obj) \ + $(wildcard *~) $(wildcard *.err) \ + $(wildcard .\#*) core $(EXE) + + +# Rules for compiling individual source files... + +$(BINDIR)/%.o: $(SRCDIR)/%.cpp + $(CC) -c -o $@ $< $(CXXFLAGS) + +$(BINDIR)/%.o: $(SRCDIR)/%.c + $(CC) -c -o $@ $< $(CFLAGS) + +$(BINDIR)/%.o: $(SRCDIR)/%.asm + $(ASM) $(ASMFLAGS) -o $@ $< + +.PHONY: all bindir blackshades +all: blackshades + +blackshades: $(BINDIR) $(OBJS) + $(LINKER) -o $(EXE) $(OBJS) $(LDFLAGS) + +$(BINDIR) : + $(MAKE) bindir + +bindir: + mkdir -p $(BINDIR) + +distclean: clean + +clean: + rm -f $(CLEANUP) + rm -rf $(BINDIR) + +# end of Makefile. + + diff --git a/blackshades_revenge/Readme b/blackshades_revenge/Readme new file mode 100644 index 0000000..3498a77 --- /dev/null +++ b/blackshades_revenge/Readme @@ -0,0 +1,117 @@ +Black Shades +By David Rosen + +Please do not give a vote unless you are running in OS 9, Black Shades can run under OS X but only under emulation which does not work nearly as well. + +Controls: +WASD = walk +shift = run +mouse = look +control = crouch/zoom +click = fire (while aiming) or smash (while running) or pick up gun (while crouching over a body and not aiming) or disarm (while not aiming) +q = aim or un-aim (important for picking up guns) +r = reload +e = psychic aim +z = toggle soul release +space = dive (while running forwards) + +keys for debug mode: + +tab = 3rdperson toggle +f = Force Pushª :) +shift-x = switch weapons + +Thats it + +Instructions: +Try to keep your VIP (the guy in white) alive as long as possible. The assassins will all try to shoot or stab him to death. You must do all you can to prevent this. Your reputation has preceded you, so the VIP has absolute confidence in your abilities and will completely ignore all the assassins. When an assassin is aiming at your VIP with a gun, you will psychicly see a line of sight extending from him to your VIP. This line will narrow and redden until it disappears and the assassin fires. Depending on the situation it may be best just to shoot the assassin(s), or to dive and tackle the VIP to the ground to avoid the bullet. Unfortunately your psychic powers do not show the line of sight of knife-wielding assassins. + +If you are feeling overwhelmed you can use psychic aiming to temporarily speed up your thought processes and aim your shots better. If there are no visible enemies you may want to release your soul and look for nearby enemies. When your soul is released your VIP pulsates between blue and red, civilians between black and red, and assassins are solid red. + +If you die or your VIP is killed.. the level restarts. If you are are interested in the theory behind this: you are a psychic bodyguard, so you can see small distances into the future. The failure only occured in a possible future which you are now going to try and avoid. + +The scoring system consists of: +150 points for a successful disarm +300 points for destroying a zombie (by blowing its head off) +100+50x points for completing a mission where x is the mission number (i.e. 450 points for completing mission 3) +75 points for incapacitating an assassin + +50 if he had a knife +-300 points for hurting a civilian +-200 points for allowing the VIP to die +The penalty for failing to protect the VIP is halved if you kill the assassin. + +You can edit levels by setting "Custom levels" to 1 in the config and editing the customlevels.txt file in the data folder. + +Weapons: +Bare Hands: Smack people with them. Or if you want to be nice, walk or stand (don't run) near somebody with a gun and take it away. + +Knife: Like bare hands, but deadly and with longer range. Look out for knife-wielding assassins, they are the most dangerous. + +Handgun: One shot with this should be enough to incapacitate any human target, but they may remain conscious for a second (this can be bad if they are about to stab your VIP, aim for the head) + +Magnum: Not as much ammo as the vanilla handgun, but one shot is an instantenous kill + +Assault Rifle: This weapon has quite a kick and is bigger and more unwieldy than the handguns, but it has a large magazine and can fire quickly if necessary + +Sniper Rifle: A bit more powerful than the magnum, with a scope. Very difficult to aim unless you are zoomed in (zoom by holding the control key) + +Shotgun: Aim and shoot. Very powerful but somewhat inaccurate. + +Grenade: Hold down the mouse button to take out the pin, release the button to throw it. Crouch to change your mind and put +the pin back in. You can knock people out if you hit them in the head, or of course you can just blow them to pieces. + +Troubleshooting: +The only known bugs are: +¥It doesn't work too well under classic emulation +¥Occasional collision detection issues +¥Turning virtual memory off can cause speed issues + +History: +11-6 to 11-9 main menu, score, etc. +10-9 to 11-6 better ai, gibbing, added zombies, weather, knife, shotgun, misc. stuff +10-8 shooting delay/ effect +10-6 added rich vip guy +10-5 bug fixes, gibbing, slomo psychicness +10-4 bug fixes, blood toggle, environments, falling damage +10-1 worked on menu, pathfinding +9-27 added black shades, bug fixes, added some IDG sounds, better collision, config.txt +9-22 bug fixes +9-21 mouse smoothing, better aiming, different blood +9-20 fixed street clipping, grenades working, more blood +9-19 fixed grenade faces, fixed some assassin AI, fixed penetration bugs +9-18 started assassin AI, some more assassin AI, some work on grenades +9-17 faster aiming/crouching, VBL sync, slightly improved control sensitivity stuff +9-16 glock added, penetrating sniper rounds, better scope, different zooming +9-15 suicide, improved bashing, npcs can carry guns, reloading, headshot sound, camera positioned better, handgun +9-14 rifle bashing, aim modifications, redder headshots, speed +9-13 everything in one folder, stationary 3rd person cam toggle, visible bullets, some sound stuff +9-12 crouching, duck to snipe, pain animations +9-11 more fluid aiming, different costumes, assault rifle, health system, impact reaction, kill counter +9-10 sniper rifle scope, bullets, sounds +9-9 bug fix +9-8 sniper rifle added (fires blanks, can't zoom), ragdoll system improved, ragdoll sounds +9-7 smooth transition to pointing arms, walking, better running, skeletal 'ragdoll' system + collisions +9-6 fixed sound bug +9-5 Added distance people sprites (very far view distance, faster also) Added limit to # of people per block, more even spacing, added pointing arms (pistol aiming without the pistol) +9-4 Added random civilian placement system (populated entire city instead of a block) +9-3 Too Busy +9-2 Too Busy +9-1 Too Busy +8-31 Started basic civilian AI +8-30 Fog fixed on ground and sky, better skeletal animation, pre-calced rotations for joints +8-29 Real Lifeª intervened, no time +8-28 Air control added, some collision fixed, occluding people, sky plane, ground does not occlude +8-27 looking up/down changes animation, editors updated to CW 8, animation editor tweaks, optimised a bit +8-26 look at previous soul position when going back into body, sound fx added, movement speed tweaks, can't see body while soul is released +8-25 black sunglasses idea(prevent visions) "dark shades" or "black shades" name +psychic vision effect added +better collision added +8-24 working under CW 8 +8-23 collision detection on street (with sidewalk+buildings) +8-22 collision detection models + firstperson view +8-21 psychic bodyguard idea +8-20 basic city engine, skeletal animation from glfighters2 pre-alpha, player+building models, jogger group + +Main menu music is included with permission from musician John Graham, Copyright 2002. +Due to legal difficulties all other music is composed by me at the last minute based on some nice loops made by Carlos Camacho, hence the 'programmer music'. +Also many thanks to my other friends and beta testers, and to artist David Drew for modelling the assault rifle, sniper rifle, handgun, shotgun and grenade. \ No newline at end of file diff --git a/blackshades_revenge/Readme.html b/blackshades_revenge/Readme.html new file mode 100644 index 0000000..b60b655 --- /dev/null +++ b/blackshades_revenge/Readme.html @@ -0,0 +1,138 @@ + + + + + + + + + + + + + +

Black Shades
By David Rosen
Wolfire +Software

Ported to Windows by Henry Kropf
Simisen +Interactive


Controls:
WASD = +walk
shift = run
mouse = look
control = +crouch/zoom
click = fire (while aiming) or smash (while +running) or pick up gun (while crouching over a body and not aiming) +or disarm (while not aiming)
q = aim or un-aim (important +for picking up guns)
r = reload
e = psychic aim
z += toggle soul release
space = dive (while running +forwards)

keys for debug mode:

tab = 3rdperson +toggle
f = Force Pushª :)
shift-x = switch +weapons

Thats it

Instructions:
Try to +keep your VIP (the guy in white) alive as long as possible. The +assassins will all try to shoot or stab him to death. You must do all +you can to prevent this. Your reputation has preceded you, so the VIP +has absolute confidence in your abilities and will completely ignore +all the assassins. When an assassin is aiming at your VIP with a gun, +you will psychicly see a line of sight extending from him to your +VIP. This line will narrow and redden until it disappears and the +assassin fires. Depending on the situation it may be best just to +shoot the assassin(s), or to dive and tackle the VIP to the ground to +avoid the bullet. Unfortunately your psychic powers do not show the +line of sight of knife-wielding assassins.

If you are feeling +overwhelmed you can use psychic aiming to temporarily speed up your +thought processes and aim your shots better. If there are no visible +enemies you may want to release your soul and look for nearby +enemies. When your soul is released your VIP pulsates between blue +and red, civilians between black and red, and assassins are solid +red.

If you die or your VIP is killed.. the level restarts. If +you are are interested in the theory behind this: you are a psychic +bodyguard, so you can see small distances into the future. The +failure only occured in a possible future which you are now going to +try and avoid.

Scoring:
150 points for a +successful disarm
300 points for destroying a zombie (by blowing +its head off)
100+50x points for completing a mission where x is +the mission number (i.e. 450 points for completing mission 3)
75 +points for incapacitating an assassin
+50 if he had a knife
-300 +points for hurting a civilian
-200 points for allowing the VIP to +die
The penalty for failing to protect the VIP is halved if you +kill the assassin.

+

+

Custom Levels:
You can +edit levels by setting "Custom levels" to 1 in the config +and editing the customlevels.txt file in the data +folder.

Weapons:
Bare Hands: Smack people +with them. Or if you want to be nice, walk or stand (don't run) near +somebody with a gun and take it away.

Knife: Like bare +hands, but deadly and with longer range. Look out for knife-wielding +assassins, they are the most dangerous.

Handgun: One +shot with this should be enough to incapacitate any human target, but +they may remain conscious for a second (this can be bad if they are +about to stab your VIP, aim for the head)

Magnum: Not +as much ammo as the vanilla handgun, but one shot is an instantenous +kill

Assault Rifle: This weapon has quite a kick and is +bigger and more unwieldy than the handguns, but it has a large +magazine and can fire quickly if necessary

Sniper Rifle: +A bit more powerful than the magnum, with a scope. Very difficult to +aim unless you are zoomed in (zoom by holding the control +key)

Shotgun: Aim and shoot. Very powerful but somewhat +inaccurate.

Grenade: Hold down the mouse button to take +out the pin, release the button to throw it. Crouch to change your +mind and put
the pin back in. You can knock people out if you hit +them in the head, or of course you can just blow them to +pieces.

+Inverted Mouse and Config.txt
Windows users can change the invert mouse element in +config.txt to 1 to activate inverted vertical mouse behavior.

+Original +Development History:
11-6 to 11-9 main menu, score, +etc.
10-9 to 11-6 better ai, gibbing, added zombies, weather, +knife, shotgun, misc. stuff
10-8 shooting delay/ effect
10-6 +added rich vip guy
10-5 bug fixes, gibbing, slomo psychicness
10-4 +bug fixes, blood toggle, environments, falling damage
10-1 worked +on menu, pathfinding
9-27 added black shades, bug fixes, added +some IDG sounds, better collision, config.txt
9-22 bug fixes
9-21 +mouse smoothing, better aiming, different blood
9-20 fixed street +clipping, grenades working, more blood
9-19 fixed grenade faces, +fixed some assassin AI, fixed penetration bugs
9-18 started +assassin AI, some more assassin AI, some work on grenades
9-17 +faster aiming/crouching, VBL sync, slightly improved control +sensitivity stuff
9-16 glock added, penetrating sniper rounds, +better scope, different zooming
9-15 suicide, improved bashing, +npcs can carry guns, reloading, headshot sound, camera positioned +better, handgun
9-14 rifle bashing, aim modifications, redder +headshots, speed
9-13 everything in one folder, stationary 3rd +person cam toggle, visible bullets, some sound stuff
9-12 +crouching, duck to snipe, pain animations
9-11 more fluid aiming, +different costumes, assault rifle, health system, impact reaction, +kill counter
9-10 sniper rifle scope, bullets, sounds
9-9 bug +fix
9-8 sniper rifle added (fires blanks, can't zoom), ragdoll +system improved, ragdoll sounds
9-7 smooth transition to pointing +arms, walking, better running, skeletal 'ragdoll' system + +collisions
9-6 fixed sound bug
9-5 Added distance people +sprites (very far view distance, faster also) Added limit to # of +people per block, more even spacing, added pointing arms (pistol +aiming without the pistol)
9-4 Added random civilian placement +system (populated entire city instead of a block)
9-3 Too Busy
9-2 +Too Busy
9-1 Too Busy
8-31 Started basic civilian AI
8-30 +Fog fixed on ground and sky, better skeletal animation, pre-calced +rotations for joints
8-29 Real Lifeª intervened, no time
8-28 +Air control added, some collision fixed, occluding people, sky plane, +ground does not occlude
8-27 looking up/down changes animation, +editors updated to CW 8, animation editor tweaks, optimised a +bit
8-26 look at previous soul position when going back into body, +sound fx added, movement speed tweaks, can't see body while soul is +released
8-25 black sunglasses idea(prevent visions) "dark +shades" or "black shades" name
psychic vision +effect added
better collision added
8-24 working under CW +8
8-23 collision detection on street (with +sidewalk+buildings)
8-22 collision detection models + firstperson +view
8-21 psychic bodyguard idea
8-20 basic city engine, +skeletal animation from glfighters2 pre-alpha, player+building +models, jogger group

Main menu music is included with +permission from musician John Graham, Copyright 2002.
Due to legal +difficulties all other music is composed by me at the last minute +based on some nice loops made by Carlos Camacho, hence the +'programmer music'.
Also many thanks to my other friends and beta +testers, and to artist David Drew for modelling the assault rifle, +sniper rifle, handgun, shotgun and grenade.

+ + \ No newline at end of file diff --git a/blackshades_revenge/Source/AGL_DSp.cpp b/blackshades_revenge/Source/AGL_DSp.cpp new file mode 100644 index 0000000..eace870 --- /dev/null +++ b/blackshades_revenge/Source/AGL_DSp.cpp @@ -0,0 +1,242 @@ +/**> HEADER FILES <**/ +#include "AGL_DSp.h" +#include "Alerts.h" + + +/**> GLOBAL VARIABLES <**/ +DSpContextAttributes gDSpContextAttributes; // Global DrawSprocket context attributes +DSpContextReference gDSpContext; // The global DrawSprocket context +AGLContext gOpenGLContext; // The global OpenGL (AGL) context + + +/********************> ToolboxInit() <*****/ +void ToolboxInit( void ) +{ + + MaxApplZone(); + + InitGraf( &qd.thePort ); + InitFonts(); + InitWindows(); + InitMenus(); + TEInit(); + InitDialogs( 0L ); + InitCursor(); + +} + +/********************> HasAppearance() <*****/ +Boolean HasAppearance( void ) +{ + + OSErr error; + SInt32 response; + Boolean appearancePresent = false; + Boolean appearance101present = false; + Boolean appearance110present = false; + Boolean inCompatibilityMode = false; + + error = Gestalt( gestaltAppearanceAttr, &response ); + + // If Gestalt returns no error and the bit in response represented by the constant + // gestaltAppearanceExists is set, proceed, otherwise exit with an error message. + + if ( error == noErr && ( BitTst( &response, 31 - gestaltAppearanceExists ) ) ) + { + // At least Version 1.0 is present. Set a flag. + appearancePresent = true; + + // If the bit in response represented by the constant gestaltAppearanceCompatMode + // is set, system-wide Appearance is off. The result of this check will be + // relevant only where Versions 1.0 through 1.0.3 are present. + if( BitTst( &response, 31 - gestaltAppearanceCompatMode ) ) + inCompatibilityMode = true; + + // Call Gestalt again with the gestaltAppearanceVersion selector. + Gestalt( gestaltAppearanceVersion, &response ); + + // If the low order word in response is 0x0101, Version 1.0.1, 1.0.2, or 1.0.3 is + // present. If the low order word in response is 0x0110, Version 1.1 is available. + if( response == 0x00000101 ) + appearance101present = true; + else if( response == 0x00000110 ) + appearance110present = true; + } + /*else + { + StopAlert( kNoAppearanceAlert, nil ); + ExitToShell(); + }*/ + + // Register this app as an Appearance Client + //RegisterAppearanceClient(); + + return appearancePresent; + +} + +/********************> SetupScreen() <*****/ +CGrafPtr SetupScreen( int width, int height ) +{ + + OSStatus theError; + CGrafPtr theFrontBuffer; + + // Start DrawSprocket + theError = DSpStartup(); + if( theError ) + FatalErrorAlert( kErr_DSpStartupFailed, theError ); + + // Set the Context Attributes + gDSpContextAttributes.displayWidth = width; + gDSpContextAttributes.displayHeight = height; + gDSpContextAttributes.colorNeeds = kDSpColorNeeds_Require; + gDSpContextAttributes.displayDepthMask = kDSpDepthMask_32; + gDSpContextAttributes.backBufferDepthMask = kDSpDepthMask_32; + gDSpContextAttributes.displayBestDepth = 32; + gDSpContextAttributes.backBufferBestDepth = 32; + gDSpContextAttributes.pageCount = 1; + + // Find the best context for our attributes + theError = DSpFindBestContext( &gDSpContextAttributes, &gDSpContext ); + if( theError != noErr ) + FatalErrorAlert( kErr_DSpFindBestContextFailed, theError ); // This function is in my Alerts.cpp + + // Reserve that context + theError = DSpContext_Reserve( gDSpContext, &gDSpContextAttributes ); + if( theError != noErr ) + FatalErrorAlert( kErr_DSpContext_ReserveFailed, theError ); + + // Fade out + theError = DSpContext_FadeGammaOut( NULL, NULL ); + if( theError != noErr ) + FatalErrorAlert( kErr_DSpFadeFailed, theError ); + + // Activate the context + theError = DSpContext_SetState( gDSpContext, kDSpContextState_Active ); + if( theError != noErr ) + { + // Fade back in the display before dying + theError = DSpContext_FadeGammaIn( NULL, NULL ); + + // Now do the fatal error alert + FatalErrorAlert( kErr_ActivateContextFailed, theError ); + } + + // Fade in + theError = DSpContext_FadeGammaIn( NULL, NULL ); + if( theError != noErr ) + FatalErrorAlert( kErr_DSpFadeFailed, theError ); + + // Create a window to draw in + CreateWindow( theFrontBuffer, width, height ); + + return theFrontBuffer; + +} + +/********************> CreateWindow() <*****/ +void CreateWindow( CGrafPtr &theFrontBuffer, int width, int height ) +{ + + Rect rect; + AuxWinHandle awh; + CTabHandle theColorTable; + OSErr error; + RGBColor backColor = { 0xFFFF, 0xFFFF, 0xFFFF }; + RGBColor foreColor = { 0x0000, 0x0000, 0x0000 }; + + // Set the window rect + rect.top = rect.left = 0; + DSpContext_LocalToGlobal( gDSpContext, ( Point* )&rect ); + rect.right = rect.left + width; + rect.bottom = rect.top + height; + + // Create a new color window + theFrontBuffer = ( CGrafPtr )NewCWindow( NULL, &rect, "\p", 0, plainDBox, kMoveToFront, 0, 0 ); + + // set the content color of the window to black to avoid a white flash when the window appears. + if ( GetAuxWin( ( WindowPtr )theFrontBuffer, &awh ) ) + { + theColorTable = ( **awh ).awCTable; + error = HandToHand( ( Handle* )&theColorTable ); + if ( error ) + DebugStr( "\pOut of memory!" ); + + ( **theColorTable ).ctTable[wContentColor].rgb.red = 0; + ( **theColorTable ).ctTable[wContentColor].rgb.green = 0; + ( **theColorTable ).ctTable[wContentColor].rgb.blue = 0; + + CTabChanged( theColorTable ); + + // the color table will be disposed by the window manager when the window is disposed + SetWinColor( ( WindowPtr )theFrontBuffer, ( WCTabHandle )theColorTable ); + } + + // Show the window + ShowWindow( ( GrafPtr )theFrontBuffer ); + SetPort( ( GrafPtr )theFrontBuffer ); + + // Set current pen colors + RGBForeColor( &foreColor ); + RGBBackColor( &backColor ); + +} + +/********************> ShutdownScreen() <*****/ +void ShutdownScreen( CGrafPtr theFrontBuffer ) +{ + + DSpContext_FadeGammaOut( NULL, NULL ); + DisposeWindow( ( WindowPtr )theFrontBuffer ); + DSpContext_SetState( gDSpContext, kDSpContextState_Inactive ); + DSpContext_FadeGammaIn( NULL, NULL ); + DSpContext_Release( gDSpContext ); + DSpShutdown(); + +} + +/********************> SetupAGL() <*****/ +AGLContext SetupAGL( AGLDrawable window ) +{ + GLint attrib[] = { AGL_RGBA, AGL_DEPTH_SIZE, 24, AGL_DOUBLEBUFFER, AGL_NONE }; + AGLPixelFormat format; + AGLContext context; + GLboolean ok; + + // Choose an rgb pixel format + format = aglChoosePixelFormat( NULL, 0, attrib ); + if ( format == NULL ) + return NULL; + + // Create an AGL context + context = aglCreateContext( format, NULL ); + if ( context == NULL ) + return NULL; + + // Attach the window to the context + ok = aglSetDrawable( context, window ); + if ( !ok ) + return NULL; + + // Make the context the current context + ok = aglSetCurrentContext( context ); + if ( !ok ) + return NULL; + + // The pixel format is no longer needed so get rid of it + aglDestroyPixelFormat( format ); + + return context; + +} + +/********************> CleanupAGL() <*****/ +void CleanupAGL( AGLContext context ) +{ + + aglSetCurrentContext( NULL ); + aglSetDrawable( context, NULL ); + aglDestroyContext( context ); + +} diff --git a/blackshades_revenge/Source/AGL_DSp.h b/blackshades_revenge/Source/AGL_DSp.h new file mode 100644 index 0000000..4c1d531 --- /dev/null +++ b/blackshades_revenge/Source/AGL_DSp.h @@ -0,0 +1,41 @@ +#pragma once + +#ifndef _AGL_DSP_H_ +#define _AGL_DSP_H_ + + +/**> HEADER FILES <**/ +#include // ANSI C cross platform headers +#include +#include // DrawSprocket +#include // Apple's OpenGL +#include // Used for setting perspective and making objects +#include // Used for loading images + + +/**> CONSTANT DECLARATIONS <**/ +#define kMoveToFront kFirstWindowOfClass + +// Screen Dimensions +#define SCREEN_WIDTH 640 +#define SCREEN_HEIGHT 480 + + +/**> GLOBAL VARIABLES <**/ +extern DSpContextAttributes gDSpContextAttributes; // Global DrawSprocket context attributes +extern DSpContextReference gDSpContext; // The global DrawSprocket context +extern AGLContext gOpenGLContext; // The global OpenGL (AGL) context + // Note: These are actually defined in AGL_DSp.cpp + + +/**> FUNCTION PROTOTYPES <**/ +void ToolboxInit( void ); +Boolean HasAppearance( void ); +CGrafPtr SetupScreen( int width, int height ); +void CreateWindow( CGrafPtr &theFrontBuffer, int width, int height ); +void ShutdownScreen( CGrafPtr theFrontBuffer ); +AGLContext SetupAGL( AGLDrawable window ); +void CleanupAGL( AGLContext context ); + + +#endif \ No newline at end of file diff --git a/blackshades_revenge/Source/Alerts.cpp b/blackshades_revenge/Source/Alerts.cpp new file mode 100644 index 0000000..acfefae --- /dev/null +++ b/blackshades_revenge/Source/Alerts.cpp @@ -0,0 +1,93 @@ +/**> HEADER FILES <**/ +#include "Alerts.h" + + +/********************> SelectResolution() <*****/ +int SelectResolution( void ) +{ + + DialogPtr dialog; + Boolean dialogDone = false; + short itemHit, itemType; + Handle okItem; + Handle resolutionItem; + Rect itemRect; + int selectionNum; + + // Load the dialog + dialog = GetNewDialog( kResID_DLOG_SelectResolution, nil, kMoveToFront ); + + // Display the dialog + ShowWindow( dialog ); + SetPort( dialog ); + + // Load dialog items + SetDialogDefaultItem( dialog, iOK ); + SetDialogTracksCursor( dialog, true ); + GetDialogItem( dialog, iOK, &itemType, &okItem, &itemRect ); + GetDialogItem( dialog, iResolutionPopUp, &itemType, &resolutionItem, &itemRect ); + + // Set item values + SetControlValue( ( ControlHandle )resolutionItem, i640x480 ); + + + while ( !dialogDone ) + { + + ModalDialog( nil, &itemHit ); + + switch( itemHit ) + { + case iOK: + dialogDone = true; + // Get the item number selected int the popup + selectionNum = GetControlValue( ( ControlHandle )resolutionItem ); + break; + case iResolutionPopUp: + // We don't actually need to do anything here + break; + } + + } + + DisposeDialog( dialog ); + + // Return the item selected in the popup menu + return selectionNum; +} + +/********************> MessageAlert() <*****/ +void MessageAlert( unsigned char *theMessage ) +{ + + // Set parameter ^0 to our message (I could set up to three, but for simplicity's sake I won't) + ParamText( ( unsigned char * )theMessage, NULL, NULL, NULL ); + + // Do the Alert + NoteAlert( kResID_ALRT_MessageAlert, nil ); + +} + +/********************> FatalErrorAlert() <*****/ +void FatalErrorAlert( UInt16 errorNum, OSErr osError ) +{ + + Str15 errNumStr; + Str255 mainMessage; + + // Convert the OSErr to a string + NumToString( osError, errNumStr ); + + // Get the error description (inErrorDesc) from the STR# resource + GetIndString( mainMessage, kResID_STRn_ErrorStrings, errorNum ); + + // Set the parameters (^0 and ^1) in the ALRT to our error messages + ParamText( mainMessage, errNumStr, NULL, NULL ); + + // Do the alert (which now has our messages in it) + StopAlert( kResID_ALRT_ErrorAlert, NULL ); + + // Quit + exit( EXIT_SUCCESS ); + +} diff --git a/blackshades_revenge/Source/Alerts.h b/blackshades_revenge/Source/Alerts.h new file mode 100644 index 0000000..5db7938 --- /dev/null +++ b/blackshades_revenge/Source/Alerts.h @@ -0,0 +1,44 @@ +#ifndef _MYALERTS_H_ +#define _MYALERTS_H_ + + +/**> HEADER FILES <**/ +#include +#include + + +/**> CONSTANT DECLARATIONS <**/ +#define kMoveToFront kFirstWindowOfClass +// Alerts +#define kResID_ALRT_MessageAlert 128 +#define kResID_ALRT_ErrorAlert 129 +// Dialogs +#define kResID_DLOG_SelectResolution 130 +#define iOK 1 +#define iResolutionPopUp 2 +// Menus +#define mResolution 128 +#define i640x480 1 +#define i800x600 2 +#define i1024x768 3 +// String resources +#define kResID_STRn_ErrorStrings 128 +// Misc +#define kInsignificantConstant7454955 0 + +// Error numbers +#define kErr_DSpFindBestContextFailed 1 +#define kErr_DSpContext_ReserveFailed 2 +#define kErr_ActivateContextFailed 3 +#define kErr_DSpStartupFailed 4 +#define kErr_DSpFadeFailed 5 +#define kErr_AGLContext_CreationFailed 6 + + +/**> FUNCTION PROTOTYPES <**/ +int SelectResolution( void ); +void MessageAlert( unsigned char *theMessage ); +void FatalErrorAlert( UInt16 errorNum, OSErr osError ); + + +#endif \ No newline at end of file diff --git a/blackshades_revenge/Source/Camera.cpp b/blackshades_revenge/Source/Camera.cpp new file mode 100644 index 0000000..950c12d --- /dev/null +++ b/blackshades_revenge/Source/Camera.cpp @@ -0,0 +1,9 @@ +/**> HEADER FILES <**/ +#include "Camera.h" + + +void Camera::Apply() +{ + glTranslatef(-position.x,-position.y,-position.z); +} + diff --git a/blackshades_revenge/Source/Camera.h b/blackshades_revenge/Source/Camera.h new file mode 100644 index 0000000..78e33fc --- /dev/null +++ b/blackshades_revenge/Source/Camera.h @@ -0,0 +1,33 @@ +#ifndef _CAMERA_H_ +#define _CAMERA_H_ + + +/**> HEADER FILES <**/ +#ifdef WIN32 +#include +#endif + +#ifdef OS9 +#include +#else +#include +#endif + +#include "Quaternions.h" + +class Camera +{ + public: + XYZ position; + XYZ oldposition; + XYZ targetoffset; + + float rotation, rotation2; + float oldrotation, oldrotation2; + float oldoldrotation, oldoldrotation2; + float visrotation, visrotation2; + void Apply(); +}; + +#endif + diff --git a/blackshades_revenge/Source/Constants.h b/blackshades_revenge/Source/Constants.h new file mode 100644 index 0000000..ba3139e --- /dev/null +++ b/blackshades_revenge/Source/Constants.h @@ -0,0 +1,173 @@ +#ifndef _CONSTANTS_H_ +#define _CONSTANTS_H_ + +#define max_joints 50 +#define max_frames 50 +#define max_muscles 100 +#define gravity -25 + +#define bullethole 0 +#define crater 1 +#define bloodpool 2 + +#define idleanim 0 +#define joganim 1 +#define pistolaimanim 2 +#define walkanim 3 +#define rifleholdanim 4 +#define rifleaimanim 5 +#define assaultrifleaimanim 6 +#define crouchanim 7 +#define headpainanim 8 +#define chestpainanim 9 +#define stomachpainanim 10 +#define rightarmpainanim 11 +#define leftarmpainanim 12 +#define rightlegpainanim 13 +#define leftlegpainanim 14 +#define riflehitanim 15 +#define grenadeaimanim 16 +#define grenadechargeanim 17 +#define grenadethrowanim 18 +#define zombieeatanim 19 +#define zombiejoganim 20 +#define zombiewalkanim 21 +#define getupfrontanim 22 +#define getupbackanim 23 +#define lyinganim 24 +#define diveanim 25 +#define throwanim 26 +#define thrownanim 27 + +#define nogun 0 +#define sniperrifle 1 +#define assaultrifle 2 +#define handgun1 3 +#define handgun2 4 +#define grenade 5 +#define knife 6 +#define shotgun 7 + +#define sniperriflemodel 0 +#define assaultriflemodel 1 +#define handgunbasemodel 2 +#define handgunslidemodel 3 +#define handgun2basemodel 4 +#define handgun2slidemodel 5 +#define grenadebasemodel 6 +#define grenadepinmodel 7 +#define grenadespoonmodel 8 +#define knifemodel 9 +#define shotgunmodel 10 + +#define visionsound 0 +#define soulinsound 1 +#define souloutsound 2 +#define footstepsound 3 +#define bodylandsound 8 +#define headlandsound 9 +#define riflesound 10 +#define bodyhitsound 11 +#define wallhitsound 12 +#define machinegunsound 13 +#define nearbulletsound 14 +#define headwhacksound 15 +#define headshotsound 16 +#define reloadsound 17 +#define clicksound 18 +#define pistol1sound 19 +#define pistol2sound 20 +#define pinpullsound 21 +#define pinreplacesound 22 +#define grenadethrowsound 23 +#define bouncesound 24 +#define bounce2sound 25 +#define explosionsound 26 +#define bodywhacksound 27 +#define rainsound 28 +#define losesound 29 +#define disguisekillsound 30 +#define knifeslashsound 31 +#define shotgunsound 32 +#define mainmenusong 33 +#define shootsong 34 +#define knifesong 35 +#define zombiesong 36 + +#define src_visionsound 0 +#define src_soulinsound 0 +#define src_souloutsound 1 +#define src_footstepsound 2 +#define src_bodylandsound 3 +#define src_headlandsound 4 +#define src_riflesound 5 +#define src_bodyhitsound 6 +#define src_wallhitsound 7 +#define src_machinegunsound 5 +#define src_nearbulletsound 5 +#define src_headwhacksound 5 +#define src_headshotsound 5 +#define src_reloadsound 5 +#define src_clicksound 5 +#define src_pistol1sound 5 +#define src_pistol2sound 5 +#define src_pinpullsound 8 +#define src_pinreplacesound 9 +#define src_grenadethrowsound 5 +#define src_bouncesound 10 +#define src_bounce2sound 11 +#define src_explosionsound 12 +#define src_bodywhacksound 13 +// not 14? +#define src_rainsound 15 +#define src_losesound 5 +#define src_disguisekillsound 5 +#define src_knifeslashsound 5 +#define src_shotgunsound 5 +#define src_mainmenusong 14 +#define src_shootsong 14 +#define src_knifesong 14 +#define src_zombiesong 14 + +#define src_songslot 14 + +#define sunny_environment 0 +#define foggy_environment 1 +#define snowy_environment 2 +#define rainy_environment 3 +#define firey_environment 4 +#define night_environment 5 + +#define randomshoot_type 0 +#define zombie_type 1 +#define soldiers_type 2 +#define snipers_type 3 +#define stabber_type 4 + +#define shotdelayamount 3 + +#define fleshtone1 240/255 +#define fleshtone2 183/255 +#define fleshtone3 132/255 + +#define headmodel 0 +#define chestmodel 1 +#define abdomenmodel 2 +#define upperarmmodel 3 +#define lowerarmmodel 4 +#define handmodel 5 +#define upperlegmodel 6 +#define lowerlegmodel 7 +#define footmodel 8 + +#define policecostume 0 +#define bodyguardcostume 1 +#define casualcostumes 2 +#define vipcostume 6 + +#define numcasual 4 + +#define soundscalefactordefault 10 + +#endif + diff --git a/blackshades_revenge/Source/Decals.cpp b/blackshades_revenge/Source/Decals.cpp new file mode 100644 index 0000000..612b89c --- /dev/null +++ b/blackshades_revenge/Source/Decals.cpp @@ -0,0 +1,449 @@ +#include "Decals.h" + +extern double multiplier; +extern bool slomo; +extern Fog fog; +extern bool blood; +extern float fogcolorr; +extern float fogcolorg; +extern float fogcolorb; +//Functions +extern float sinefluct; +extern int environment; +extern Model gunmodels[10]; +extern Camera camera; +extern float precipitationhorz; +extern float precipitationvert; +extern float precipitationdensity; +extern float snowdelay; + +int Decals::MakeDecal(int atype, XYZ location, float size, XYZ normal, int poly, Model *model, XYZ move, float rotation){ + int major=0; + float normalv[3]; + XYZ right; + XYZ up; + XYZ nothing; + XYZ axis[3]; + XYZ temp; + + nothing=0; + + axis[0].x=1; + axis[1].y=1; + axis[2].z=1; + + normalv[0]=abs(normal.x); + normalv[1]=abs(normal.y); + normalv[2]=abs(normal.z); + + + if(normalv[1]>normalv[major])major=1; + if(normalv[2]>normalv[major])major=2; + + if (normalv[0] == 1 || normalv[1] == 1 || normalv[2] == 1) + { + if ((major == 0 && normal.x > 0) || major == 1){ + right=0; + right.z=-1;} + else if (major == 0){ + right=0; + right.z=1;} + else { + right=0; + right.x=normal.z;} + } + else + CrossProduct(axis[major], normal, &right); + + CrossProduct(normal, right, &up); + Normalise(&up); + Normalise(&right); + + float count; + float count2; + float countinc=1/size; + if(countinc<.01)countinc=.01; + if(countinc>.2)countinc=.2; + float normaloffset=.02; + int good; + + numpoints[howmanydecals]=0; + points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing - right - up) * (size/3) /*+ normal/100*/; + texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = 0; + texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = 0; + if((move.x==0&&move.z==0&&rotation==0)|| + LineFacetd(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25, model->vertex[model->Triangles[poly].vertex[0]], model->vertex[model->Triangles[poly].vertex[1]], model->vertex[model->Triangles[poly].vertex[2]],normal,&temp) + )numpoints[howmanydecals]++; + else { + good=-1; + count=1-countinc; + while(good==-1&&count>-1){ + texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = 0; + texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = .5-count/2; + points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing - right - up*count) * (size/3); + count-=countinc; + good=model->LineCheck2(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25,&temp,move,rotation); + } + if(good!=-1)numpoints[howmanydecals]++; + good=-1; + count=1-countinc; + while(good==-1&&count>-1){ + texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = .5-count/2; + texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = 0; + points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing - right*count - up) * (size/3); + count-=countinc; + good=model->LineCheck2(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25,&temp,move,rotation); + } + if(good!=-1)numpoints[howmanydecals]++; + if(good==-1){ + good=-1; + count2=1-countinc; + while(good==-1&&count2>-1){ + count=1-countinc; + while(good==-1&&count>-1){ + texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = .5-count2/2; + texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = .5-count/2; + points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing - right*count2 - up*count) * (size/3); + count-=countinc; + good=model->LineCheck2(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25,&temp,move,rotation); + } + count2-=countinc; + } + if(good!=-1)numpoints[howmanydecals]++; + } + } + + points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing + right - up) * (size/3) /*+ normal/100*/; + texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = 1; + texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = 0; + if((move.x==0&&move.y==0&&move.z==0&&rotation==0)|| + LineFacetd(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25, model->vertex[model->Triangles[poly].vertex[0]], model->vertex[model->Triangles[poly].vertex[1]], model->vertex[model->Triangles[poly].vertex[2]],normal,&temp) + )numpoints[howmanydecals]++; + else { + good=-1; + count=1-countinc; + while(good==-1&&count>-1){ + texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = .5+count/2; + texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = 0; + points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing + right*count - up) * (size/3); + count-=countinc; + good=model->LineCheck2(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25,&temp,move,rotation); + } + if(good!=-1)numpoints[howmanydecals]++; + good=-1; + count=1-countinc; + while(good==-1&&count>-1){ + texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = 1; + texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = .5-count/2; + points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing + right - up*count) * (size/3); + count-=countinc; + good=model->LineCheck2(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25,&temp,move,rotation); + } + if(good!=-1)numpoints[howmanydecals]++; + if(good==-1){ + good=-1; + count2=1-countinc; + while(good==-1&&count2>-1){ + count=1-countinc; + while(good==-1&&count>-1){ + texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = .5+count2/2; + texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = .5-count/2; + points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing + right*count2 - up*count) * (size/3); + count-=countinc; + good=model->LineCheck2(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25,&temp,move,rotation); + } + count2-=countinc; + } + if(good!=-1)numpoints[howmanydecals]++; + } + } + + points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing + right + up) * (size/3) /*+ normal/100*/; + texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = 1; + texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = 1; + if((move.x==0&&move.y==0&&move.z==0&&rotation==0)|| + LineFacetd(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25, model->vertex[model->Triangles[poly].vertex[0]], model->vertex[model->Triangles[poly].vertex[1]], model->vertex[model->Triangles[poly].vertex[2]],normal,&temp) + )numpoints[howmanydecals]++; + else { + good=-1; + count=1-countinc; + while(good==-1&&count>-1){ + texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = 1; + texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = .5+count/2; + points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing + right + up*count) * (size/3); + count-=countinc; + good=model->LineCheck2(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25,&temp,move,rotation); + } + if(good!=-1)numpoints[howmanydecals]++; + good=-1; + count=1-countinc; + while(good==-1&&count>-1){ + texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = .5+count/2; + texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = 1; + points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing + right*count + up) * (size/3); + count-=countinc; + good=model->LineCheck2(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25,&temp,move,rotation); + } + if(good!=-1)numpoints[howmanydecals]++; + if(good==-1){ + good=-1; + count2=1-countinc; + while(good==-1&&count2>-1){ + count=1-countinc; + while(good==-1&&count>-1){ + texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = .5+count2/2; + texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = .5+count/2; + points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing + right*count2 + up*count) * (size/3); + count-=countinc; + good=model->LineCheck2(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25,&temp,move,rotation); + } + count2-=countinc; + } + if(good!=-1)numpoints[howmanydecals]++; + } + } + + points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing - right + up) * (size/3) /*+ normal/100*/; + texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = 0; + texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = 1; + if((move.x==0&&move.y==0&&move.z==0&&rotation==0)|| + LineFacetd(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25, model->vertex[model->Triangles[poly].vertex[0]], model->vertex[model->Triangles[poly].vertex[1]], model->vertex[model->Triangles[poly].vertex[2]],normal,&temp) + )numpoints[howmanydecals]++; + else { + good=-1; + count=1-countinc; + while(good==-1&&count>-1){ + texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = .5-count/2; + texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = 1; + points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing - right*count + up) * (size/3); + count-=countinc; + good=model->LineCheck2(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25,&temp,move,rotation); + } + if(good!=-1)numpoints[howmanydecals]++; + good=-1; + count=1-countinc; + while(good==-1&&count>-1){ + texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = 0; + texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = .5+count/2; + points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing - right + up*count) * (size/3); + count-=countinc; + good=model->LineCheck2(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25,&temp,move,rotation); + } + if(good!=-1)numpoints[howmanydecals]++; + if(good==-1){ + good=-1; + count2=1-countinc; + while(good==-1&&count2>-1){ + count=1-countinc; + while(good==-1&&count>-1){ + texcoordsx[howmanydecals*8+numpoints[howmanydecals]] = .5-count2/2; + texcoordsy[howmanydecals*8+numpoints[howmanydecals]] = .5+count/2; + points[howmanydecals*8+numpoints[howmanydecals]] = location + (nothing - right*count2 + up*count) * (size/3); + count-=countinc; + good=model->LineCheck2(points[howmanydecals*8+numpoints[howmanydecals]]+normal/25,points[howmanydecals*8+numpoints[howmanydecals]]-normal/25,&temp,move,rotation); + } + count2-=countinc; + } + if(good!=-1)numpoints[howmanydecals]++; + } + } + for(int i=0;i=0){ + numpoints[which]=numpoints[howmanydecals-1]; + alivetime[which]=alivetime[howmanydecals-1]; + type[which]=type[howmanydecals-1]; + for(int i=0;i0){howmanydecals--;} + } + + return 0; +} + +void Decals::LoadBulletHoleTexture(char *fileName) +{ + TGAImageRec *tempTexture; + GLuint type; + + //Load Image + tempTexture = LoadTGA( fileName ); + //Is it valid? + if(tempTexture){ + //Alpha channel? + if ( tempTexture->bpp == 24 ) + type = GL_RGB; + else + type = GL_RGBA; + + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + + glGenTextures( 1, &bulletholetextureptr ); + glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + + glBindTexture( GL_TEXTURE_2D, bulletholetextureptr); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + + gluBuild2DMipmaps( GL_TEXTURE_2D, type, tempTexture->sizeX, tempTexture->sizeY, type, GL_UNSIGNED_BYTE, tempTexture->data ); + free( tempTexture->data ); + free( tempTexture ); + } +} + +void Decals::LoadBloodTexture(char *fileName, int which) +{ + TGAImageRec *tempTexture; + GLuint type; + + //Load Image + tempTexture = LoadTGA( fileName ); + //Is it valid? + if(tempTexture){ + //Alpha channel? + if ( tempTexture->bpp == 24 ) + type = GL_RGB; + else + type = GL_RGBA; + + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + + glGenTextures( 1, &bloodtextureptr[which] ); + glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + + glBindTexture( GL_TEXTURE_2D, bloodtextureptr[which]); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + + gluBuild2DMipmaps( GL_TEXTURE_2D, type, tempTexture->sizeX, tempTexture->sizeY, type, GL_UNSIGNED_BYTE, tempTexture->data ); + free( tempTexture->data ); + free( tempTexture ); + } +} + +void Decals::LoadCraterTexture(char *fileName) +{ + TGAImageRec *tempTexture; + GLuint type; + + //Load Image + tempTexture = LoadTGA( fileName ); + //Is it valid? + if(tempTexture){ + //Alpha channel? + if ( tempTexture->bpp == 24 ) + type = GL_RGB; + else + type = GL_RGBA; + + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + + glGenTextures( 1, &cratertextureptr ); + glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + + glBindTexture( GL_TEXTURE_2D, cratertextureptr); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + + gluBuild2DMipmaps( GL_TEXTURE_2D, type, tempTexture->sizeX, tempTexture->sizeY, type, GL_UNSIGNED_BYTE, tempTexture->data ); + free( tempTexture->data ); + free( tempTexture ); + } +} + +void Decals::DoStuff() +{ + for(int i=0;i10&&(type[i]==bullethole||type[i]==crater))DeleteDecal(i); + if(alivetime[i]>20&&(type[i]==bloodpool))DeleteDecal(i); + } +} + +void Decals::draw() +{ + glAlphaFunc(GL_GREATER, 0.01); + + float bloodpoolspeed=1; + + glDepthFunc(GL_LEQUAL); + glEnable(GL_BLEND); + glEnable(GL_CULL_FACE); + glEnable(GL_TEXTURE_2D); + glEnable(GL_LIGHTING); + glDepthMask(0); + glAlphaFunc(GL_GREATER, 0.01); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); + glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_POLYGON_OFFSET_FILL); + for(int i=0;i=bloodpoolspeed*.2&&alivetime[i]=bloodpoolspeed*.4&&alivetime[i]=bloodpoolspeed*.6&&alivetime[i]=bloodpoolspeed*.8&&alivetime[i]=bloodpoolspeed*1&&alivetime[i]=bloodpoolspeed*1.2&&alivetime[i]=bloodpoolspeed*1.4&&alivetime[i]=bloodpoolspeed*1.6&&alivetime[i]=bloodpoolspeed*1.8&&alivetime[i]=bloodpoolspeed*2.0)glBindTexture(GL_TEXTURE_2D, bloodtextureptr[10]); + if(type[i]==bloodpool&&alivetime[i]=bloodpoolspeed*2.0)glColor4f(1,1,1,20-alivetime[i]); + + glPushMatrix(); + glBegin(GL_TRIANGLE_FAN); + for(int j=0;j=bloodpoolspeed*.2&&alivetime[i]=bloodpoolspeed*.4&&alivetime[i]=bloodpoolspeed*.6&&alivetime[i]=bloodpoolspeed*.8&&alivetime[i]=bloodpoolspeed*1&&alivetime[i]=bloodpoolspeed*1.2&&alivetime[i]=bloodpoolspeed*1.4&&alivetime[i]=bloodpoolspeed*1.6&&alivetime[i]=bloodpoolspeed*1.8&&alivetime[i] +#endif + +#ifdef OS9 +#include +#include +#include "glut.h" +#else +#include +#endif +#include "Files.h" +#include "TGALoader.h" +#include "Quaternions.h" +#include "Camera.h" +#include "Models.h" +#include "Fog.h" +// +// Model Structures +// + +#define maxdecals 120 + +class Decals{ + public: + GLuint bulletholetextureptr; + GLuint cratertextureptr; + GLuint bloodtextureptr[11]; + + int howmanydecals; + + int type[maxdecals]; + + XYZ points[8*maxdecals]; + int numpoints[maxdecals]; + float texcoordsx[8*maxdecals]; + float texcoordsy[8*maxdecals]; + float alivetime[maxdecals]; + + void draw(); + + int DeleteDecal(int which); + int MakeDecal(int atype, XYZ location, float size, XYZ normal, int poly, Model *model, XYZ move, float rotation); + + void DoStuff(); + void LoadBulletHoleTexture(char *fileName); + void LoadCraterTexture(char *fileName); + void LoadBloodTexture(char *fileName, int which); + + ~Decals() { + glDeleteTextures( 1, (const GLuint *)bulletholetextureptr ); + glDeleteTextures( 1, (const GLuint *)cratertextureptr ); + glDeleteTextures( 11, (const GLuint *)bloodtextureptr ); + }; +}; + +#endif + diff --git a/blackshades_revenge/Source/Files.cpp b/blackshades_revenge/Source/Files.cpp new file mode 100644 index 0000000..f955ca1 --- /dev/null +++ b/blackshades_revenge/Source/Files.cpp @@ -0,0 +1,197 @@ +#include "Files.h" + +#ifdef OS9 +short Files::OpenFile(Str255 Name) +{ + short volume; + char filename[33]; + short tFile; + tFile=-1; + Point ptOrigin = { 0, 0 }; + volume = 0; + sprintf (filename, "%s", Name); + SetVol( nil, volume ); + CtoPstr( filename ); + FSOpen( (Pstr) filename, volume,&tFile ); + PtoCstr( (Pstr) filename ); + sFile=tFile; + return( tFile ); +} +#endif + +/* +#ifdef WIN32 +FILE *Files::OpenFile(Str255 Name) +{ + //MEGA NEON - stub function + + return 0; +} +#endif +*/ + +/* +#ifdef OS9 +short Files::OpenNewFile( SFReply *psfReply, + OSType osTypeCreator, + OSType osTypeType ) +{ + sFile = 0; + OSErr osErr; + + SetVol( nil, psfReply->vRefNum ); + osErr = Create( psfReply->fName, psfReply->vRefNum, osTypeCreator, osTypeType ); + + if ( osErr == dupFNErr ) + { + FSDelete( psfReply->fName, psfReply->vRefNum ); + Create( psfReply->fName, psfReply->vRefNum, osTypeCreator, osTypeType ); + } + + FSOpen( psfReply->fName, psfReply->vRefNum, &sFile ); + + return( sFile ); +} + + +short Files::PromptForSaveAS( short sPromptID, + short sNameID, + Str255 str255NamePrompt, + OSType osTypeCreator, + OSType osTypeType, + SFReply *psfReply ) +{ + Str255 str255Prompt; + Str255 str255Name; + sFile = 0; + Point ptOrigin = { 0, 0 }; + + GetIndString( str255Prompt, FILE_STRINGS, sPromptID ); + + if ( !str255NamePrompt ) + GetIndString( str255Name, FILE_STRINGS, sNameID ); + + else + memcpy( str255Name, str255NamePrompt, *str255NamePrompt + 1 ); + + SFPutFile( ptOrigin, str255Prompt, str255Name, nil, psfReply ); + + if ( psfReply->good ) + { + sFile = OpenNewFile( psfReply, osTypeCreator, osTypeType ); + } + + return( sFile ); +} + +#endif + + +short Files::OpenSavedGame(Str255 Name) +{ + Point ptOrigin = { 0, 0 }; + sSavedGameVolume = 0; + sprintf (szSavedGameName, "%s", Name); + SetVol( nil, sSavedGameVolume ); + CtoPstr( szSavedGameName ); + FSOpen( (Pstr) szSavedGameName, sSavedGameVolume,&sFile ); + PtoCstr( (Pstr) szSavedGameName ); + return( sFile ); +} + +short Files::OpenFileDialog() +{ + Point ptOrigin = { 0, 0 }; + sFile = 0; + SFReply sfReply; + SFTypeList sfTypeList = { 'DMAP', '\p', '\p', '\p' }; + SFGetFile( ptOrigin, "\p", nil, 1, sfTypeList, nil, &sfReply ); + + if ( sfReply.good ) + { + PtoCstr( sfReply.fName ); + strcpy( szSavedGameName, (Cstr) sfReply.fName ); + } + + if ( sfReply.good ) + { + sSavedGameVolume = sfReply.vRefNum; + SetVol( nil, sSavedGameVolume ); + + CtoPstr( szSavedGameName ); + + FSOpen( (Pstr) szSavedGameName, sSavedGameVolume,&sFile ); + + PtoCstr( (Pstr) szSavedGameName ); + } + + return( sFile ); +} + +void Files::StartSave() +{ + int x,y; + SFReply sfReply; + sFile = 0; + long lSize; + long lLongSize = sizeof( long ); + + CtoPstr( szSavedGameName ); + + sFile = PromptForSaveAS( SAVE_GAME_STRING, 0, (Pstr)szSavedGameName,'DAVD', 'DMAP', &sfReply ); + + PtoCstr((Pstr) szSavedGameName ); + + if ( sFile ) + { + sSavedGameVolume = sfReply.vRefNum; + PtoCstr( sfReply.fName ); + strcpy( szSavedGameName, (Cstr)sfReply.fName ); + } + + else + { + sfReply.vRefNum = sSavedGameVolume; + strcpy( (Cstr) sfReply.fName, szSavedGameName ); + CtoPstr( (Cstr)sfReply.fName ); + + sFile = OpenNewFile( &sfReply, 'GLF2', 'SKLT' ); + } + +} + +void Files::EndSave() +{ + int x,y; + SFReply sfReply; + long lSize; + long lLongSize = sizeof( long ); + + if ( sFile ) + FSClose( sFile ); + +} + +void Files::StartLoad() +{ +#ifdef WIN32 + bool bLoaded = false; +#else + Boolean bLoaded = false; +#endif + + long lSize; + long lLongSize = sizeof( long ); + + int x,y,kl; + sFile=OpenFileDialog(); + +} + +void Files::EndLoad() +{ + + if (sFile) + FSClose( sFile ); +} +*/ \ No newline at end of file diff --git a/blackshades_revenge/Source/Files.h b/blackshades_revenge/Source/Files.h new file mode 100644 index 0000000..b8e4356 --- /dev/null +++ b/blackshades_revenge/Source/Files.h @@ -0,0 +1,123 @@ +#ifndef _FILES_H_ +#define _FILES_H_ + +#ifdef WIN32 +#include +//#include "macdefines.h" +#include "Support.h" +#endif + +#include +#include // Header File For Standard functions +#include // Header File For Standard Input/Output +#include +#include +#include +#include +#include +#include +#ifdef OS9 +#include "gl.h" // Header File For The OpenGL32 Library +#include "glu.h" // Header File For The GLu32 Library +#include "tk.h" // Header File For The Glaux Library +#else +#include +#include +#endif +#ifdef OS9 +#include +#include +#include "AGL_DSp.h" // Header for OpenGL and DrawSprocket Functions +#include "Alerts.h" // Header for Dialogs and alerts for this application +#endif +#include "MacInput.h" // Header for Special Mac Input functions +#ifdef OS9 +#include "glm.h" +#include +#endif + +#define FILE_STRINGS 130 +#define Pstr unsigned char * +#define Cstr char * + +#define FILE_ERROR_ALERT 138 +#define OLD_SAVE_VERSION 139 +#define UNREADABLE_SCORES_ALERT 140 + +#define SAVE_WARNING_ID 132 +#define PB_SAVE 1 +#define PB_CANCEL 2 +#define PB_DONT_SAVE 3 + +#define FILE_ERROR_STRINGS 129 +#define FILE_ERROR_PREFIX 1 +#define FILE_ERROR_SUFFIX 2 + +#define SAVE_WARNING_STRINGS 132 + +#define FILE_STRINGS 130 +#define SAVE_GAME_STRING 1 +#define SAVE_SCORES_STRING 2 +#define SCORES_NAME_STRING 3 +#define SAVE_JOURNAL_STRING 4 +#define JOURNAL_NAME_STRING 5 +#define UNTITLED_STRING 6 +#define SAVE_FORM_STRING 7 +#define FORM_NAME_STRING 8 + +#define REGISTRATION_FORM 136 + +#define FILE_NAME_SIZE 32 +#define ERROR_LENGTH 80 + +/**> Files Opening <**/ +class Files +{ + public: + char szSavedGameName[FILE_NAME_SIZE + 1]; + short sSavedGameVolume; +#ifdef OS9 + SFReply sfReply; + Boolean bGameSaved; +#endif +#ifdef OS9 + short sFile; +#else + FILE *sFile; +#endif + +#ifdef OS9 + short OpenFile(Str255 Name); +#else + FILE *OpenFile(Str255 Name); + Files() : sFile(NULL) { } + + ~Files() + { + if (sFile != NULL) + fclose(sFile); + } +#endif + +#ifdef OS9 + short PromptForSaveAS( short sPromptID, + short sNameID, + Str255 str255NamePrompt, + OSType osTypeCreator, + OSType osTypeType, + SFReply *psfReply ); + short OpenNewFile( SFReply *psfReply, OSType osTypeCreator, OSType osTypeType ); +#endif + short OpenSavedGame(Str255 Name); + short OpenFileDialog(); + void LoadNamedMap(Str255 Name); + void LoadGame(Str255 Name, int animnum); + + void LoadMap(); + void StartSave(); + void EndSave(); + void StartLoad(); + void EndLoad(); +}; + +#endif diff --git a/blackshades_revenge/Source/Fog.cpp b/blackshades_revenge/Source/Fog.cpp new file mode 100644 index 0000000..20aa3a9 --- /dev/null +++ b/blackshades_revenge/Source/Fog.cpp @@ -0,0 +1,54 @@ +/**> HEADER FILES <**/ +#include "Fog.h" + +void Fog::SetFog(float colorR, float colorG, float colorB, float fStart, float fEnd, float Density) +{ + fogColor[0]=colorR; + fogColor[1]=colorG; + fogColor[2]=colorB; + fogColor[3]=1; + fogStart=fStart; + fogEnd=fEnd; + fogDensity=Density; + fogMode=GL_LINEAR; + + glFogi(GL_FOG_MODE,fogMode); + glFogfv(GL_FOG_COLOR,fogColor); + glFogf(GL_FOG_DENSITY,fogDensity); + glFogi(GL_FOG_HINT,GL_DONT_CARE); + glFogf(GL_FOG_START,fogStart); + glFogf(GL_FOG_END,fogEnd); + + glEnable(GL_FOG); +} + +void Fog::TempFog(float colorR, float colorG, float colorB) +{ + GLfloat tempfogColor[4]; + tempfogColor[0]=colorR; + tempfogColor[1]=colorG; + tempfogColor[2]=colorB; + tempfogColor[3]=1; + + glFogi(GL_FOG_MODE,fogMode); + glFogfv(GL_FOG_COLOR,tempfogColor); + glFogf(GL_FOG_DENSITY,fogDensity); + glFogi(GL_FOG_HINT,GL_DONT_CARE); + glFogf(GL_FOG_START,fogStart); + glFogf(GL_FOG_END,fogEnd); + + glEnable(GL_FOG); +} + +void Fog::ResetFog() +{ + glFogi(GL_FOG_MODE,fogMode); + glFogfv(GL_FOG_COLOR,fogColor); + glFogf(GL_FOG_DENSITY,fogDensity); + glFogi(GL_FOG_HINT,GL_DONT_CARE); + glFogf(GL_FOG_START,fogStart); + glFogf(GL_FOG_END,fogEnd); + + glEnable(GL_FOG); +} + diff --git a/blackshades_revenge/Source/Fog.h b/blackshades_revenge/Source/Fog.h new file mode 100644 index 0000000..7ce3ebb --- /dev/null +++ b/blackshades_revenge/Source/Fog.h @@ -0,0 +1,33 @@ +#ifndef _FOG_H_ +#define _FOG_H_ + + +/**> HEADER FILES <**/ + +#ifdef WIN32 +#include +#endif + +#ifdef OS9 +#include +#else +#include +#endif +#include "Quaternions.h" + + +class Fog{ + public: + GLfloat fogColor[4]; + GLint fogMode; + GLfloat fogDensity; + GLfloat fogStart; + GLfloat fogEnd; + + void SetFog(float colorR, float colorG, float colorB, float fStart, float fEnd, float fogDensity); + void TempFog(float colorR, float colorG, float colorB); + void ResetFog(); +}; + +#endif + diff --git a/blackshades_revenge/Source/Frustum.cpp b/blackshades_revenge/Source/Frustum.cpp new file mode 100644 index 0000000..f52813d --- /dev/null +++ b/blackshades_revenge/Source/Frustum.cpp @@ -0,0 +1,249 @@ +#ifdef WIN32 +#include +#endif +#include +#ifdef OS9 +#include "gl.h" +#else +#include +#endif + +#include "Frustum.h" + +void FRUSTUM:: + GetFrustum() { + float projmatrix[16]; + float mvmatrix[16]; + float clip[16]; + float t; + + glGetFloatv(GL_PROJECTION_MATRIX, projmatrix); + glGetFloatv(GL_MODELVIEW_MATRIX, mvmatrix); + + // Combine the matrices + clip[0] = mvmatrix[0] * projmatrix[0] + mvmatrix[1] * projmatrix[4] + mvmatrix[2] * projmatrix[8] + mvmatrix[3] * projmatrix[12]; + clip[1] = mvmatrix[0] * projmatrix[1] + mvmatrix[1] * projmatrix[5] + mvmatrix[2] * projmatrix[9] + mvmatrix[3] * projmatrix[13]; + clip[2] = mvmatrix[0] * projmatrix[2] + mvmatrix[1] * projmatrix[6] + mvmatrix[2] * projmatrix[10] + mvmatrix[3] * projmatrix[14]; + clip[3] = mvmatrix[0] * projmatrix[3] + mvmatrix[1] * projmatrix[7] + mvmatrix[2] * projmatrix[11] + mvmatrix[3] * projmatrix[15]; + + clip[4] = mvmatrix[4] * projmatrix[0] + mvmatrix[5] * projmatrix[4] + mvmatrix[6] * projmatrix[8] + mvmatrix[7] * projmatrix[12]; + clip[5] = mvmatrix[4] * projmatrix[1] + mvmatrix[5] * projmatrix[5] + mvmatrix[6] * projmatrix[9] + mvmatrix[7] * projmatrix[13]; + clip[6] = mvmatrix[4] * projmatrix[2] + mvmatrix[5] * projmatrix[6] + mvmatrix[6] * projmatrix[10] + mvmatrix[7] * projmatrix[14]; + clip[7] = mvmatrix[4] * projmatrix[3] + mvmatrix[5] * projmatrix[7] + mvmatrix[6] * projmatrix[11] + mvmatrix[7] * projmatrix[15]; + + clip[8] = mvmatrix[8] * projmatrix[0] + mvmatrix[9] * projmatrix[4] + mvmatrix[10] * projmatrix[8] + mvmatrix[11] * projmatrix[12]; + clip[9] = mvmatrix[8] * projmatrix[1] + mvmatrix[9] * projmatrix[5] + mvmatrix[10] * projmatrix[9] + mvmatrix[11] * projmatrix[13]; + clip[10] = mvmatrix[8] * projmatrix[2] + mvmatrix[9] * projmatrix[6] + mvmatrix[10] * projmatrix[10] + mvmatrix[11] * projmatrix[14]; + clip[11] = mvmatrix[8] * projmatrix[3] + mvmatrix[9] * projmatrix[7] + mvmatrix[10] * projmatrix[11] + mvmatrix[11] * projmatrix[15]; + + clip[12] = mvmatrix[12] * projmatrix[0] + mvmatrix[13] * projmatrix[4] + mvmatrix[14] * projmatrix[8] + mvmatrix[15] * projmatrix[12]; + clip[13] = mvmatrix[12] * projmatrix[1] + mvmatrix[13] * projmatrix[5] + mvmatrix[14] * projmatrix[9] + mvmatrix[15] * projmatrix[13]; + clip[14] = mvmatrix[12] * projmatrix[2] + mvmatrix[13] * projmatrix[6] + mvmatrix[14] * projmatrix[10] + mvmatrix[15] * projmatrix[14]; + clip[15] = mvmatrix[12] * projmatrix[3] + mvmatrix[13] * projmatrix[7] + mvmatrix[14] * projmatrix[11] + mvmatrix[15] * projmatrix[15]; + + // Right plane + frustum[0][0] = clip[3] - clip[0]; + frustum[0][1] = clip[7] - clip[4]; + frustum[0][2] = clip[11] - clip[8]; + frustum[0][3] = clip[15] - clip[12]; + + // Left plane + frustum[1][0] = clip[3] + clip[0]; + frustum[1][1] = clip[7] + clip[4]; + frustum[1][2] = clip[11] + clip[8]; + frustum[1][3] = clip[15] + clip[12]; + + // Bottom plane + frustum[2][0] = clip[3] + clip[1]; + frustum[2][1] = clip[7] + clip[5]; + frustum[2][2] = clip[11] + clip[9]; + frustum[2][3] = clip[15] + clip[13]; + + // Top plane + frustum[3][0] = clip[3] - clip[1]; + frustum[3][1] = clip[7] - clip[5]; + frustum[3][2] = clip[11] - clip[9]; + frustum[3][3] = clip[15] - clip[13]; + + // Far plane + frustum[4][0] = clip[3] - clip[2]; + frustum[4][1] = clip[7] - clip[6]; + frustum[4][2] = clip[11] - clip[10]; + frustum[4][3] = clip[15] - clip[14]; + + // Near plane + frustum[5][0] = clip[3] + clip[2]; + frustum[5][1] = clip[7] + clip[6]; + frustum[5][2] = clip[11] + clip[10]; + frustum[5][3] = clip[15] + clip[14]; + + /* normalize the right plane */ + t = sqrtf(frustum[0][0]*frustum[0][0] + + frustum[0][1]*frustum[0][1] + + frustum[0][2]*frustum[0][2]); + frustum[0][0] /= t; + frustum[0][1] /= t; + frustum[0][2] /= t; + frustum[0][3] /= t; + + /* calculate left plane */ + frustum[1][0] = clip[ 3] + clip[ 0]; + frustum[1][1] = clip[ 7] + clip[ 4]; + frustum[1][2] = clip[11] + clip[ 8]; + frustum[1][3] = clip[15] + clip[12]; + + /* normalize the left plane */ + t = sqrtf(frustum[1][0]*frustum[1][0] + + frustum[1][1]*frustum[1][1] + + frustum[1][2]*frustum[1][2]); + frustum[1][0] /= t; + frustum[1][1] /= t; + frustum[1][2] /= t; + frustum[1][3] /= t; + + /* calculate the bottom plane */ + frustum[2][0] = clip[ 3] + clip[ 1]; + frustum[2][1] = clip[ 7] + clip[ 5]; + frustum[2][2] = clip[11] + clip[ 9]; + frustum[2][3] = clip[15] + clip[13]; + + /* normalize the bottom plane */ + t = sqrtf(frustum[2][0]*frustum[2][0] + + frustum[2][1]*frustum[2][1] + + frustum[2][2]*frustum[2][2]); + frustum[2][0] /= t; + frustum[2][1] /= t; + frustum[2][2] /= t; + frustum[2][3] /= t; + + /* calculate the top plane */ + frustum[3][0] = clip[ 3] - clip[ 1]; + frustum[3][1] = clip[ 7] - clip[ 5]; + frustum[3][2] = clip[11] - clip[ 9]; + frustum[3][3] = clip[15] - clip[13]; + + /* normalize the top plane */ + t = sqrtf(frustum[3][0]*frustum[3][0] + + frustum[3][1]*frustum[3][1] + + frustum[3][2]*frustum[3][2]); + frustum[3][0] /= t; + frustum[3][1] /= t; + frustum[3][2] /= t; + frustum[3][3] /= t; + + /* calculate the far plane */ + frustum[4][0] = clip[ 3] - clip[ 2]; + frustum[4][1] = clip[ 7] - clip[ 6]; + frustum[4][2] = clip[11] - clip[10]; + frustum[4][3] = clip[15] - clip[14]; + + /* normalize the far plane */ + t = sqrtf(frustum[4][0]*frustum[4][0] + + frustum[4][1]*frustum[4][1] + + frustum[4][2]*frustum[4][2]); + frustum[4][0] /= t; + frustum[4][1] /= t; + frustum[4][2] /= t; + frustum[4][3] /= t; + + /* calculate the near plane */ + frustum[5][0] = clip[ 3] + clip[ 2]; + frustum[5][1] = clip[ 7] + clip[ 6]; + frustum[5][2] = clip[11] + clip[10]; + frustum[5][3] = clip[15] + clip[14]; + + /* normalize the near plane */ + t = sqrtf(frustum[5][0]*frustum[5][0] + + frustum[5][1]*frustum[5][1] + + frustum[5][2]*frustum[5][2]); + frustum[5][0] /= t; + frustum[5][1] /= t; + frustum[5][2] /= t; + frustum[5][3] /= t; + +} + +int FRUSTUM:: + CubeInFrustum(float x, float y, float z, float size) { + int c, c2; + + c2 = 0; + for(int i=0; i<6; i++) { + c=0; + if(frustum[i][0] * (x-size) + frustum[i][1] * (y-size) + frustum[i][2] * (z-size) + frustum[i][3] > 0) + c++; + if(frustum[i][0] * (x+size) + frustum[i][1] * (y-size) + frustum[i][2] * (z-size) + frustum[i][3] > 0) + c++; + if(frustum[i][0] * (x-size) + frustum[i][1] * (y+size) + frustum[i][2] * (z-size) + frustum[i][3] > 0) + c++; + if(frustum[i][0] * (x+size) + frustum[i][1] * (y+size) + frustum[i][2] * (z-size) + frustum[i][3] > 0) + c++; + if(frustum[i][0] * (x-size) + frustum[i][1] * (y-size) + frustum[i][2] * (z+size) + frustum[i][3] > 0) + c++; + if(frustum[i][0] * (x+size) + frustum[i][1] * (y-size) + frustum[i][2] * (z+size) + frustum[i][3] > 0) + c++; + if(frustum[i][0] * (x-size) + frustum[i][1] * (y+size) + frustum[i][2] * (z+size) + frustum[i][3] > 0) + c++; + if(frustum[i][0] * (x+size) + frustum[i][1] * (y+size) + frustum[i][2] * (z+size) + frustum[i][3] > 0) + c++; + if(c==0) + return 0; + if(c==8) + c2++; + } + if(c2>=6) + return 2; + else + return 1; +} + +int FRUSTUM:: + CubeInFrustum(float x, float y, float z, float size, float height) { + int c, c2; + + c2 = 0; + for(int i=0; i<6; i++) { + c=0; + if(frustum[i][0] * (x-size) + frustum[i][1] * (y-height) + frustum[i][2] * (z-size) + frustum[i][3] > 0) + c++; + if(frustum[i][0] * (x+size) + frustum[i][1] * (y-height) + frustum[i][2] * (z-size) + frustum[i][3] > 0) + c++; + if(frustum[i][0] * (x-size) + frustum[i][1] * (y+height) + frustum[i][2] * (z-size) + frustum[i][3] > 0) + c++; + if(frustum[i][0] * (x+size) + frustum[i][1] * (y+height) + frustum[i][2] * (z-size) + frustum[i][3] > 0) + c++; + if(frustum[i][0] * (x-size) + frustum[i][1] * (y-height) + frustum[i][2] * (z+size) + frustum[i][3] > 0) + c++; + if(frustum[i][0] * (x+size) + frustum[i][1] * (y-height) + frustum[i][2] * (z+size) + frustum[i][3] > 0) + c++; + if(frustum[i][0] * (x-size) + frustum[i][1] * (y+height) + frustum[i][2] * (z+size) + frustum[i][3] > 0) + c++; + if(frustum[i][0] * (x+size) + frustum[i][1] * (y+height) + frustum[i][2] * (z+size) + frustum[i][3] > 0) + c++; + if(c==0) + return 0; + if(c==8) + c2++; + } + if(c2>=6) + return 2; + else + return 1; +} + +int FRUSTUM:: + SphereInFrustum(float x, float y, float z, float radius) { + int c2; + + c2 = 0; + for(int i=0; i<6; i++) { + if(frustum[i][0] * x + frustum[i][1] * y + frustum[i][2] * z + frustum[i][3] > -1*radius) + c2++; + else + return 0; + } + if(c2>=6) + return 2; + else + return 1; +} diff --git a/blackshades_revenge/Source/Frustum.h b/blackshades_revenge/Source/Frustum.h new file mode 100644 index 0000000..1680226 --- /dev/null +++ b/blackshades_revenge/Source/Frustum.h @@ -0,0 +1,14 @@ +#ifndef FRUSTUM_H +#define FRUSTUM_H + +class FRUSTUM { + public: + float frustum[6][4]; + void GetFrustum(); + int CubeInFrustum(float, float, float, float); + int CubeInFrustum(float, float, float, float, float); + int SphereInFrustum(float, float, float, float); +}; + +#endif + diff --git a/blackshades_revenge/Source/Game.h b/blackshades_revenge/Source/Game.h new file mode 100644 index 0000000..3357603 --- /dev/null +++ b/blackshades_revenge/Source/Game.h @@ -0,0 +1,255 @@ +#ifndef _GAME_H_ +#define _GAME_H_ + +#ifdef WIN32 +#include +#endif + +#ifdef OS9 +#include +#include +#include +#else +#include +#include +#endif +#include +#include +#include +#include +#ifdef OS9 +#include +#include +#endif +#include +#ifdef OS9 +#include +#include +#endif +#ifndef OS9 + #ifdef WIN32 + #include + #include + #else + #include + #include + #endif +#endif +#ifdef OS9 +#include "alut.h" +#else + #ifdef WIN32 + #include + #include + #else + #include + #include + #endif +#endif +#include "Timer.h" +#ifdef OS9 +#include "AGL_DSp.h" +#endif +#include "MacInput.h" +#include "Quaternions.h" +#include "Camera.h" +#include "Skeleton.h" +#include "Files.h" +#include "Models.h" +#include "Text.h" +#include "TGALoader.h" +#include "Fog.h" +#include "Frustum.h" +#include "Sprites.h" +#include "Person.h" +#include "Decals.h" + +#define num_blocks 100 +#define block_spacing 360 +#define max_people 90 +#define max_people_block 20 + + +class Game +{ + public: + //Eventloop + Boolean gQuit; + float gamespeed; + double multiplier2,multiplier3,multiplier4,multiplier5,end,start,timetaken,framespersecond; + timer theTimer; + float sps; + int maxfps; +#ifdef OS9 + AGLContext gOpenGLContext; + CGrafPtr theScreen; +#endif + //Graphics + int screenwidth,screenheight; + float viewdistance; + + //GL functions + GLvoid ReSizeGLScene(float fov, float nearplane); + + int DrawGLScene(GLvoid); + int InitGL(GLvoid); + void LoadingScreen(float percent); + + //Game Functions + void HandleKeyDown( char theChar ); +#ifdef OS9 + void DoEvent( EventRecord *event ); +#endif + void ProcessSDLEvents( void ); + void EventLoop( void ); + void Tick(); + void Splat(int k); + void InitGame(); + void Dispose(); + + //Mouse + Point mouseloc; + Point oldmouseloc; + + float mouserotation,mouserotation2; + float oldmouserotation,oldmouserotation2; + float mousesensitivity; + float usermousesensitivity; + + //keyboard + + bool tabkeydown; + + //Project Specific + int cityrotation[num_blocks][num_blocks]; + int citytype[num_blocks][num_blocks]; + int citypeoplenum[num_blocks][num_blocks]; + bool drawn[num_blocks][num_blocks]; + int onblockx,onblocky; + bool cubetest; + bool disttest; + bool oldbutton; + + bool initialized; + + float flashamount; + float flashr,flashg,flashb; + + int enemystate; + + int cycle; + + bool whacked; + + float losedelay; + + XYZ bodycoords; + + FRUSTUM frustum; + Model blocks[4]; + Model blockwalls[4]; + Model blockcollide[4]; + Model blocksimplecollide[4]; + Model blockroofs[4]; + Model blockocclude; + Model sidewalkcollide; + Model street; + Model Bigstreet; + Model path; + Model blocksimple; + XYZ boundingpoints[8]; + Files files; + Text text; + int goodkills; + int badkills; + int civkills; + int machinegunsoundloop; + + bool lasersight; + bool debug; + bool vblsync; + + int blur; + bool blurness; + + int paused; + + int mainmenu; + + bool reloadtoggle; + + bool aimtoggle; + + Point olddrawmouse; + + XYZ vipgoal; + + XYZ aimer[2]; + + double eqn[4]; + + float oldrot,oldrot2; + + XYZ lastshot[2]; + bool zoom; + bool oldzoom; + + int numpeople; + float spawndelay; + + bool customlevels; + + bool musictoggle; + + float psychicpower; + + int type; + + bool slomokeydown; + + int mouseoverbutton; + int oldmouseoverbutton; + + Person person[max_people]; + + GLuint personspritetextureptr; + GLuint deadpersonspritetextureptr; + GLuint scopetextureptr; + GLuint flaretextureptr; + + bool killedinnocent; + bool gameinprogress; + bool beatgame; + bool mainmenuness; + int murderer; + float timeremaining; + int whichsong; + int oldscore; + int highscore; + int score; + int mission; + int nummissions; + int numpossibleguns; + int possiblegun[6]; + int evilprobability; + float difficulty; + bool azertykeyboard; + bool oldvisionkey; + int invertmouse; + //new stuff + int fpslimit; + int fullscreen; + int fov; + + ~Game() { + glDeleteTextures( 1, (const GLuint *)personspritetextureptr ); + glDeleteTextures( 1, (const GLuint *)deadpersonspritetextureptr ); + glDeleteTextures( 1, (const GLuint *)scopetextureptr ); + glDeleteTextures( 1, (const GLuint *)flaretextureptr ); + } + + + void getAuralCameraPosition(float *gLoc); +}; + +#endif diff --git a/blackshades_revenge/Source/GameDraw.cpp b/blackshades_revenge/Source/GameDraw.cpp new file mode 100644 index 0000000..440b878 --- /dev/null +++ b/blackshades_revenge/Source/GameDraw.cpp @@ -0,0 +1,1772 @@ +#include "Game.h" +#include "SoundFX.h" + +extern int thirdperson; + +extern double multiplier; + +extern int nocolors; + +extern int visions; + +extern unsigned int gSourceID[100]; + +extern unsigned int gSampleSet[100]; + +extern Camera camera; + +extern Sprites sprites; + +extern float camerashake; + +extern Fog fog; + +extern float fogcolorr; + +extern float fogcolorg; + +extern float fogcolorb; + +extern float sinefluct; + +extern float sinefluctprog; + +extern int environment; + +extern Decals decals; + +/*********************> DrawGLScene() <*****/ + +int Game::DrawGLScene(GLvoid) + +{ + + //Main menu + + if(mainmenu==1){ + + //Setup fast sine fluctuation + + sinefluct=sin(sinefluctprog); + + sinefluctprog+=multiplier*1.5; + + + + glLoadIdentity(); + + glClearColor(0,0,0,1); + + glDisable(GL_CLIP_PLANE0); + + glDisable(GL_FOG); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + + + //"Black Shades" + + glDisable(GL_TEXTURE_2D); + + glDisable(GL_DEPTH_TEST); // Disables Depth Testing + + glDisable(GL_CULL_FACE); + + glDisable(GL_LIGHTING); + + glBlendFunc(GL_SRC_ALPHA,GL_ONE); + + glDepthMask(0); + + glMatrixMode(GL_PROJECTION); // Select The Projection Matrix + + glPushMatrix(); // Store The Projection Matrix + + glLoadIdentity(); // Reset The Projection Matrix + + glOrtho(0,640,0,480,-100,100); // Set Up An Ortho Screen + + glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix + + //Draw smoke + + glPushMatrix(); // Store The Modelview Matrix + + glLoadIdentity(); // Reset The Modelview Matrix + + glTranslatef(60+sinefluct*40,335-sinefluct*9,0); + + glScalef(500-sinefluct*80,70+sinefluct*18,1); + + glTranslatef(.5,.5,0); + + glScalef(.5,.5,1); + + glRotatef(sinefluctprog*50,0,0,1); + + glEnable(GL_TEXTURE_2D); + + glBindTexture(GL_TEXTURE_2D, sprites.smoketextureptr); + + glEnable(GL_BLEND); + + glColor4f(1,1,1,.4+sinefluct/8); + + glBegin(GL_TRIANGLES); + + glTexCoord2f(1.0f, 1.0f); glVertex3f( 1, 1, 0.0f); + + glTexCoord2f(0.0f, 1.0f); glVertex3f(-1, 1, 0.0f); + + glTexCoord2f(1.0f, 0.0f); glVertex3f( 1,-1, 0.0f); + + glTexCoord2f(0.0f, 0.0f); glVertex3f(-1,-1, 0.0f); + + glTexCoord2f(1.0f, 0.0f); glVertex3f( 1, -1, 0.0f); + + glTexCoord2f(0.0f, 1.0f); glVertex3f(-1, 1, 0.0f); + + glEnd(); + + glPopMatrix(); + + glPushMatrix(); // Store The Modelview Matrix + + glLoadIdentity(); // Reset The Modelview Matrix + + glTranslatef(60+sinefluct*40,335-sinefluct*9,0); + + glScalef(530-sinefluct*80,50+sinefluct*18,1); + + glTranslatef(.5,.5,0); + + glScalef(.5,.5,1); + + glRotatef(-sinefluctprog*50,0,0,1); + + glEnable(GL_TEXTURE_2D); + + glBindTexture(GL_TEXTURE_2D, sprites.smoketextureptr); + + glEnable(GL_BLEND); + + glColor4f(1,1,1,.4-sinefluct/8); + + glBegin(GL_TRIANGLES); + + glTexCoord2f(1.0f, 1.0f); glVertex3f( 1, 1, 0.0f); + + glTexCoord2f(0.0f, 1.0f); glVertex3f(-1, 1, 0.0f); + + glTexCoord2f(1.0f, 0.0f); glVertex3f( 1,-1, 0.0f); + + glTexCoord2f(0.0f, 0.0f); glVertex3f(-1,-1, 0.0f); + + glTexCoord2f(1.0f, 0.0f); glVertex3f( 1, -1, 0.0f); + + glTexCoord2f(0.0f, 1.0f); glVertex3f(-1, 1, 0.0f); + + glEnd(); + + glMatrixMode(GL_PROJECTION); // Select The Projection Matrix + + glPopMatrix(); // Restore The Old Projection Matrix + + glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix + + glPopMatrix(); // Restore The Old Projection Matrix + + glDepthMask(1); + + + + //Text + + + + glEnable(GL_TEXTURE_2D); + + glColor4f(0,0,0,1); + + static char string[256]=""; + + sprintf (string, "Revenge Mod"); + + text.glPrint(100,175,string,1,2,640,480); + + + + //"New Game" + + glDisable(GL_TEXTURE_2D); + + glDisable(GL_DEPTH_TEST); // Disables Depth Testing + + glDisable(GL_CULL_FACE); + + glDisable(GL_LIGHTING); + + glBlendFunc(GL_SRC_ALPHA,GL_ONE); + + glDepthMask(0); + + glMatrixMode(GL_PROJECTION); // Select The Projection Matrix + + glPushMatrix(); // Store The Projection Matrix + + glLoadIdentity(); // Reset The Projection Matrix + + glOrtho(0,640,0,480,-100,100); // Set Up An Ortho Screen + + glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix + + //Draw smoke + + glPushMatrix(); // Store The Modelview Matrix + + glLoadIdentity(); // Reset The Modelview Matrix + + glTranslatef(120-sinefluct*40,235+sinefluct*9,0); + + glScalef(440+sinefluct*80,70-sinefluct*18,1); + + glTranslatef(.5,.5,0); + + glScalef(.5,.5,1); + + glRotatef(sinefluctprog*50,0,0,1); + + glEnable(GL_TEXTURE_2D); + + if(mouseoverbutton!=1)glBindTexture(GL_TEXTURE_2D, sprites.smoketextureptr); + + if(mouseoverbutton==1)glBindTexture(GL_TEXTURE_2D, flaretextureptr); + + glEnable(GL_BLEND); + + glColor4f(1,0,0,.5+sinefluct/6); + + glBegin(GL_TRIANGLES); + + glTexCoord2f(1.0f, 1.0f); glVertex3f( 1, 1, 0.0f); + + glTexCoord2f(0.0f, 1.0f); glVertex3f(-1, 1, 0.0f); + + glTexCoord2f(1.0f, 0.0f); glVertex3f( 1,-1, 0.0f); + + glTexCoord2f(0.0f, 0.0f); glVertex3f(-1,-1, 0.0f); + + glTexCoord2f(1.0f, 0.0f); glVertex3f( 1, -1, 0.0f); + + glTexCoord2f(0.0f, 1.0f); glVertex3f(-1, 1, 0.0f); + + glEnd(); + + glPopMatrix(); + + glPushMatrix(); // Store The Modelview Matrix + + glLoadIdentity(); // Reset The Modelview Matrix + + glTranslatef(120-sinefluct*40,235+sinefluct*9,0); + + glScalef(460+sinefluct*80,50-sinefluct*18,1); + + glTranslatef(.5,.5,0); + + glScalef(.5,.5,1); + + glRotatef(-sinefluctprog*50,0,0,1); + + glEnable(GL_TEXTURE_2D); + + if(mouseoverbutton!=1)glBindTexture(GL_TEXTURE_2D, sprites.smoketextureptr); + + if(mouseoverbutton==1)glBindTexture(GL_TEXTURE_2D, flaretextureptr); + + glEnable(GL_BLEND); + + glColor4f(1,0,0,.5-sinefluct/6); + + glBegin(GL_TRIANGLES); + + glTexCoord2f(1.0f, 1.0f); glVertex3f( 1, 1, 0.0f); + + glTexCoord2f(0.0f, 1.0f); glVertex3f(-1, 1, 0.0f); + + glTexCoord2f(1.0f, 0.0f); glVertex3f( 1,-1, 0.0f); + + glTexCoord2f(0.0f, 0.0f); glVertex3f(-1,-1, 0.0f); + + glTexCoord2f(1.0f, 0.0f); glVertex3f( 1, -1, 0.0f); + + glTexCoord2f(0.0f, 1.0f); glVertex3f(-1, 1, 0.0f); + + glEnd(); + + glMatrixMode(GL_PROJECTION); // Select The Projection Matrix + + glPopMatrix(); // Restore The Old Projection Matrix + + glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix + + glPopMatrix(); // Restore The Old Projection Matrix + + glDepthMask(1); + + + + //Text + + + + glEnable(GL_TEXTURE_2D); + + glColor4f(0,0,0,1); + + if(!gameinprogress)sprintf (string, "New Game"); + + if(gameinprogress)sprintf (string, "Resume Game"); + + text.glPrint(190-gameinprogress*10,170,string,1,1.5,640,480); + + + + //"Quit" + + glDisable(GL_TEXTURE_2D); + + glDisable(GL_DEPTH_TEST); // Disables Depth Testing + + glDisable(GL_CULL_FACE); + + glDisable(GL_LIGHTING); + + glBlendFunc(GL_SRC_ALPHA,GL_ONE); + + glDepthMask(0); + + glMatrixMode(GL_PROJECTION); // Select The Projection Matrix + + glPushMatrix(); // Store The Projection Matrix + + glLoadIdentity(); // Reset The Projection Matrix + + glOrtho(0,640,0,480,-100,100); // Set Up An Ortho Screen + + glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix + + //Draw smoke + + glPushMatrix(); // Store The Modelview Matrix + + glLoadIdentity(); // Reset The Modelview Matrix + + glTranslatef(120-sinefluct*40,112+sinefluct*9,0); + + glScalef(440+sinefluct*80,70-sinefluct*18,1); + + glTranslatef(.5,.5,0); + + glScalef(.5,.5,1); + + glRotatef(sinefluctprog*50,0,0,1); + + glEnable(GL_TEXTURE_2D); + + if(mouseoverbutton!=2)glBindTexture(GL_TEXTURE_2D, sprites.smoketextureptr); + + if(mouseoverbutton==2)glBindTexture(GL_TEXTURE_2D, flaretextureptr); + + glEnable(GL_BLEND); + + glColor4f(1,0,0,.5+sinefluct/6); + + glBegin(GL_TRIANGLES); + + glTexCoord2f(1.0f, 1.0f); glVertex3f( 1, 1, 0.0f); + + glTexCoord2f(0.0f, 1.0f); glVertex3f(-1, 1, 0.0f); + + glTexCoord2f(1.0f, 0.0f); glVertex3f( 1,-1, 0.0f); + + glTexCoord2f(0.0f, 0.0f); glVertex3f(-1,-1, 0.0f); + + glTexCoord2f(1.0f, 0.0f); glVertex3f( 1, -1, 0.0f); + + glTexCoord2f(0.0f, 1.0f); glVertex3f(-1, 1, 0.0f); + + glEnd(); + + glPopMatrix(); + + glPushMatrix(); // Store The Modelview Matrix + + glLoadIdentity(); // Reset The Modelview Matrix + + glTranslatef(120-sinefluct*40,112+sinefluct*9,0); + + glScalef(460+sinefluct*80,50-sinefluct*18,1); + + glTranslatef(.5,.5,0); + + glScalef(.5,.5,1); + + glRotatef(-sinefluctprog*50,0,0,1); + + glEnable(GL_TEXTURE_2D); + + if(mouseoverbutton!=2)glBindTexture(GL_TEXTURE_2D, sprites.smoketextureptr); + + if(mouseoverbutton==2)glBindTexture(GL_TEXTURE_2D, flaretextureptr); + + glEnable(GL_BLEND); + + glColor4f(1,0,0,.5-sinefluct/6); + + glBegin(GL_TRIANGLES); + + glTexCoord2f(1.0f, 1.0f); glVertex3f( 1, 1, 0.0f); + + glTexCoord2f(0.0f, 1.0f); glVertex3f(-1, 1, 0.0f); + + glTexCoord2f(1.0f, 0.0f); glVertex3f( 1,-1, 0.0f); + + glTexCoord2f(0.0f, 0.0f); glVertex3f(-1,-1, 0.0f); + + glTexCoord2f(1.0f, 0.0f); glVertex3f( 1, -1, 0.0f); + + glTexCoord2f(0.0f, 1.0f); glVertex3f(-1, 1, 0.0f); + + glEnd(); + + glMatrixMode(GL_PROJECTION); // Select The Projection Matrix + + glPopMatrix(); // Restore The Old Projection Matrix + + glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix + + glPopMatrix(); // Restore The Old Projection Matrix + + glDepthMask(1); + + + + //Text + + + + glEnable(GL_TEXTURE_2D); + + glColor4f(0,0,0,1); + + if(!gameinprogress)sprintf (string, "Quit"); + + if(gameinprogress)sprintf (string, "End Game"); + + text.glPrint(197-gameinprogress*15,87,string,1,1.5,640,480); + + + + //High score + + glColor4f(.5+sinefluct/5,0,0,1); + + if(!beatgame)sprintf (string, "High Score: %d", highscore); + + if(beatgame)sprintf (string, "High Score: %d *COMPLETED* Please vote for Black Shades at iDevGames.com!", highscore); + + text.glPrint(0,0,string,1,.8,640,480); + + + + //Mandatory udg text + + glColor4f(.3-sinefluct/20,.3-sinefluct/20,.3-sinefluct/20,1); + + sprintf (string, "uDevGame 2002 Entry - Visit iDevGames.com for more games!"); + + text.glPrint(500,750,string,1,.6,640,480); + + + + + //Mouse (draw) + + glMatrixMode(GL_PROJECTION); // Select The Projection Matrix + + glPushMatrix(); // Store The Projection Matrix + + glLoadIdentity(); // Reset The Projection Matrix + + glOrtho(0,screenwidth,0,screenheight,-100,100); // Set Up An Ortho Screen + + glMatrixMode(GL_MODELVIEW); + + glDisable(GL_TEXTURE_2D); + + + Point mouseloc; + + GetMouse(&mouseloc); + + mouseloc.v=screenheight-mouseloc.v; + + + glColor4f(.1,0,0,1); + + + + float size=5; + + + + glBegin(GL_TRIANGLES); + + glVertex3f(mouseloc.h,mouseloc.v,0); + + glVertex3f(mouseloc.h+2*size,mouseloc.v-2*size,0); + + glVertex3f(mouseloc.h+.5*size,mouseloc.v-2*size,0); + + glEnd(); + + + + glColor4f(1,0,0,1); + + + + glBegin(GL_QUADS); + + glVertex3f(olddrawmouse.h,olddrawmouse.v,0); + + glVertex3f(mouseloc.h,mouseloc.v,0); + + glVertex3f(mouseloc.h+2*size,mouseloc.v-2*size,0); + + glVertex3f(olddrawmouse.h+2*size,olddrawmouse.v-2*size,0); + + + + glVertex3f(olddrawmouse.h,olddrawmouse.v,0); + + glVertex3f(mouseloc.h,mouseloc.v,0); + + glVertex3f(mouseloc.h+.5*size,mouseloc.v-2*size,0); + + glVertex3f(olddrawmouse.h+.5*size,olddrawmouse.v-2*size,0); + + + + glVertex3f(olddrawmouse.h+2*size,olddrawmouse.v-2*size,0); + + glVertex3f(mouseloc.h+2*size,mouseloc.v-2*size,0); + + glVertex3f(mouseloc.h+.5*size,mouseloc.v-2*size,0); + + glVertex3f(olddrawmouse.h+.5*size,olddrawmouse.v-2*size,0); + + glEnd(); + + glPopMatrix(); + + + olddrawmouse=mouseloc; + + + //Flash + + if(flashamount>0){ + + if(flashamount>1)flashamount=1; + + flashamount-=multiplier; + + if(flashamount<0)flashamount=0; + + glDisable(GL_DEPTH_TEST); // Disables Depth Testing + + glDisable(GL_CULL_FACE); + + glDisable(GL_LIGHTING); + + glDepthMask(0); + + glMatrixMode(GL_PROJECTION); // Select The Projection Matrix + + glPushMatrix(); // Store The Projection Matrix + + glLoadIdentity(); // Reset The Projection Matrix + + glOrtho(0,screenwidth,0,screenheight,-100,100); // Set Up An Ortho Screen + + glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix + + glPushMatrix(); // Store The Modelview Matrix + + glLoadIdentity(); // Reset The Modelview Matrix + + glScalef(screenwidth,screenheight,1); + + glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + + glEnable(GL_BLEND); + + glColor4f(flashr,flashg,flashb,flashamount); + + glBegin(GL_QUADS); + + glVertex3f(0, 0, 0.0f); + + glVertex3f(256, 0, 0.0f); + + glVertex3f(256, 256, 0.0f); + + glVertex3f(0, 256, 0.0f); + + glEnd(); + + glMatrixMode(GL_PROJECTION); // Select The Projection Matrix + + glPopMatrix(); // Restore The Old Projection Matrix + + glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix + + glPopMatrix(); // Restore The Old Projection Matrix + + glEnable(GL_DEPTH_TEST); // Enables Depth Testing + + glEnable(GL_CULL_FACE); + + glDisable(GL_BLEND); + + glDepthMask(1); + + } + + } + + //If in-game + + if(mainmenu!=1){ + + //If flashing to fix menu bug, go back to menu after a frame + + if(mainmenu==2)mainmenu=1; + + glLoadIdentity(); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glEnable(GL_DEPTH_TEST); + + glDisable(GL_CLIP_PLANE0); + + //Visions + + sinefluct=sin(sinefluctprog); + + sinefluctprog+=multiplier*3; + + if(visions==0){ + + //environment light + + if(environment==sunny_environment){ + + viewdistance=2000; + + fogcolorr=.5; + + fogcolorg=.5; + + fogcolorb=.8; + + fog.SetFog(fogcolorr,fogcolorg,fogcolorb,0,viewdistance*.8,.1); + + } + + if(environment==foggy_environment){ + + viewdistance=500; + + fogcolorr=.5; + + fogcolorg=.5; + + fogcolorb=.5; + + fog.SetFog(fogcolorr,fogcolorg,fogcolorb,0,viewdistance*.8,.2); + + } + + if(environment==night_environment){ + + viewdistance=500; + + fogcolorr=.15; + + fogcolorg=.15; + + fogcolorb=.3; + + fog.SetFog(fogcolorr,fogcolorg,fogcolorb,0,viewdistance*.8,.2); + + } + + if(environment==snowy_environment){ + + viewdistance=800; + + fogcolorr=.5; + + fogcolorg=.5; + + fogcolorb=.5; + + fog.SetFog(fogcolorr,fogcolorg,fogcolorb,0,viewdistance*.8,.2); + + } + + if(environment==rainy_environment){ + + viewdistance=700; + + fogcolorr=.3; + + fogcolorg=.3; + + fogcolorb=.3; + + fog.SetFog(fogcolorr,fogcolorg,fogcolorb,0,viewdistance*.8,.2); + + } + + if(environment==firey_environment){ + + viewdistance=600; + + fogcolorr=.3; + + fogcolorg=.1; + + fogcolorb=0; + + fog.SetFog(fogcolorr,fogcolorg,fogcolorb,0,viewdistance*.8,.2); + + } + + glClearColor(fogcolorr,fogcolorg,fogcolorb,1); + + + + if(environment==sunny_environment){ + + GLfloat LightAmbient[]= { fogcolorr/4, fogcolorg/4, fogcolorb/4, 1.0f}; + + GLfloat LightDiffuse[]= { fogcolorr*1.6, fogcolorg*1.6, fogcolorr*1.6, 1.0f }; + + glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmbient); + + glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDiffuse); + + } + + if(environment!=sunny_environment){ + + GLfloat LightAmbient[]= { fogcolorr*.8, fogcolorg*.8, fogcolorb*.8, 1.0f}; + + GLfloat LightDiffuse[]= { fogcolorr*.8, fogcolorg*.8, fogcolorr*.8, 1.0f }; + + glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmbient); + + glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDiffuse); + + } + + + + glEnable(GL_LIGHT0); + + + + //Change fov if zooming with scope + + if(!zoom)ReSizeGLScene(fov,.1); + + if(zoom)ReSizeGLScene(fov/4,.6); + + nocolors=0; + + } + + + + if(visions==1){ + + //light + + GLfloat LightAmbient[]= { 0, 0, 0, 1.0f}; + + GLfloat LightDiffuse[]= { .1+sinefluct/5, 0, 0, 1.0f }; + + + + glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmbient); + + glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDiffuse); + + glEnable(GL_LIGHT0); + + + + fogcolorr=(sinefluct/4+.5); + + fogcolorg=0; + + fogcolorb=0; + + fog.SetFog(fogcolorr,fogcolorg,fogcolorb,0,viewdistance*.8*.5*(sinefluct/4+.3),sinefluct/3+.7); + + glClearColor(fogcolorr,fogcolorg,fogcolorb,1); + + ReSizeGLScene(120-sinefluct*20,.3); + + glRotatef(sinefluct*10,0,0,.1); + + nocolors=1; + + //Pitch higher if moving for effect + + + if(person[0].currentanimation==idleanim)alSourcef(SoundFX::inst()->getVisionSource(), AL_PITCH, 1); + + if(person[0].currentanimation!=idleanim)alSourcef(SoundFX::inst()->getVisionSource(), AL_PITCH, 2); + + } + + + + //Camera + + float bluramount=.1*blurness; + + blur=1-blur; + + //Set rotation/position + + if(thirdperson)glTranslatef(camera.targetoffset.x,camera.targetoffset.y,camera.targetoffset.z); + + if(thirdperson!=2&&(person[0].skeleton.free!=1||thirdperson!=0)){ + + glRotatef(camera.visrotation2+-bluramount/2+(float)blur*bluramount,1,0,0); + + glRotatef(camera.visrotation+-bluramount/2+(float)blur*bluramount,0,1,0); + + } + + if(thirdperson==0&&person[0].skeleton.free==1){ + + glRotatef(person[0].skeleton.joints[(person[0].skeleton.jointlabels[head])].rotate3,0,1,0); + + glRotatef(180-(person[0].skeleton.joints[(person[0].skeleton.jointlabels[head])].rotate2+90),0,0,1); + + glRotatef(person[0].skeleton.joints[(person[0].skeleton.jointlabels[head])].rotate1+90,0,1,0); + + } + + if(thirdperson==2){ + + glRotatef(oldrot2+-bluramount/2+(float)blur*bluramount,1,0,0); + + glRotatef(oldrot+-bluramount/2+(float)blur*bluramount,0,1,0); + + } + + //Shake camera if grenade explosion + + if(camerashake>0){ + + if(!(person[0].aiming<1||person[0].whichgun==grenade||thirdperson)){ + + camerashake=0; + + } + + glTranslatef((float)(Random()%100)/100*camerashake,(float)(Random()%100)/100*camerashake,(float)(Random()%100)/100*camerashake); + + } + + camera.Apply(); + + + + glPushMatrix(); + + glClipPlane(GL_CLIP_PLANE0, eqn); + + glDisable(GL_CLIP_PLANE0); + + glPopMatrix(); + + + + frustum.GetFrustum(); + + + + GLfloat LightPosition[]= { -.5, 1, -.8, 0.0f }; + + glLightfv(GL_LIGHT0, GL_POSITION, LightPosition); + + + + glDisable(GL_TEXTURE_2D); + + glEnable(GL_FOG); + + glEnable(GL_COLOR_MATERIAL); + + glEnable(GL_CULL_FACE); + + glDepthMask(1); + + + + //Draw street + + glPushMatrix(); + + glDepthMask(0); + + glDisable(GL_DEPTH_TEST); + + glEnable(GL_LIGHTING); + + glTranslatef(camera.position.x,0,camera.position.z); + + glScalef(viewdistance*5/100,1,viewdistance*5/100); + + if(visions==0)street.draw(.22,.22,.22); + + if(visions==1)street.draw(0,0,0); + + glEnable(GL_DEPTH_TEST); + + glDepthMask(1); + + glPopMatrix(); + + + + if(visions==0)glEnable(GL_LIGHTING); + + if(visions==1)glDisable(GL_LIGHTING); + + + + //Draw blocks + + glEnable(GL_BLEND); + +// XYZ move2; + + XYZ move; + + int beginx,endx; + + int beginz,endz; + +// int beginoccludex,endoccludex; + +// int beginoccludez,endoccludez; + + int distsquared; + + + + //Only nearby blocks + + beginx=(camera.position.x-viewdistance+block_spacing/2)/block_spacing-2; + + if(beginx<0)beginx=0; + + beginz=(camera.position.z-viewdistance+block_spacing/2)/block_spacing-2; + + if(beginz<0)beginz=0; + + + + endx=(camera.position.x+viewdistance+block_spacing/2)/block_spacing+2; + + if(endx>num_blocks-1)endx=num_blocks-1; + + endz=(camera.position.z+viewdistance+block_spacing/2)/block_spacing+2; + + if(endz>num_blocks-1)endz=num_blocks-1; + + + + bool draw; + +// int numfail; + + int whichtri; + + XYZ collpoint; + + + + for(int i=beginx;i<=endx;i++){ + + for(int j=beginz;j<=endz;j++){ + + drawn[i][j]=1; + + } + + } + + + + if(beginx(viewdistance*viewdistance+block_spacing*block_spacing ))draw=0; + + if(draw&&citytype[i][j]!=3&&!frustum.CubeInFrustum((i)*block_spacing,0,(j)*block_spacing,block_spacing))draw=0; + + if(draw&&citytype[i][j]!=3&&!frustum.SphereInFrustum(blocks[citytype[i][j]].boundingspherecenter.x+(i)*block_spacing,blocks[citytype[i][j]].boundingspherecenter.y,blocks[citytype[i][j]].boundingspherecenter.z+(j)*block_spacing,blocks[citytype[i][j]].boundingsphereradius))draw=0; + + if(draw){ + + glPushMatrix(); + + glTranslatef(i*block_spacing,0,j*block_spacing); + + glRotatef(cityrotation[i][j]*90,0,1,0); + + blocks[citytype[i][j]].draw(); + + glPopMatrix(); + + } + + if(!draw){ + + move.y=0; + + move.x=i*block_spacing; + + move.z=j*block_spacing; + + if(findDistancefast(move,camera.position)<300000)drawn[i][j]=0; + + } + + } + + } + + + + //Decals + + decals.draw(); + + + + //Occluding blocks + + beginx=(camera.position.x+block_spacing/2)/block_spacing-2; + + if(beginx<0)beginx=0; + + beginz=(camera.position.z+block_spacing/2)/block_spacing-2; + + if(beginz<0)beginz=0; + + + + endx=(camera.position.x+block_spacing/2)/block_spacing+2; + + if(endx>num_blocks-1)endx=num_blocks-1; + + endz=(camera.position.z+block_spacing/2)/block_spacing+2; + + if(endz>num_blocks-1)endz=num_blocks-1; + + + + float M[16]; + + XYZ drawpoint; + + float size=20; + + + + //Draw people + + if(visions==1)fog.SetFog(fogcolorr,fogcolorg,fogcolorb,0,viewdistance*.8*.5*(-sinefluct/4+.3),-sinefluct/3+.7); + + glColor4f(1,1,1,1); + + glEnable(GL_COLOR_MATERIAL); + + glEnable(GL_BLEND); + + for(i=0;i=0&&person[i].whichblockx=0&&person[i].whichblocky1000000)draw=0; + + if(draw) + + for(int j=beginx;j<=endx;j++){ + + for(int k=beginz;k<=endz;k++){ + + if(draw){ + + move.y=0; + + move.x=j*block_spacing; + + move.z=k*block_spacing; + + if(findDistancefast(move,camera.position)<100000){ + + whichtri=blockocclude.LineCheck2(camera.position,person[i].playercoords,&collpoint,move,0); + + if(whichtri!=-1)draw=0; + + } + + } + + } + + } + + if(draw){ + + move.y=0; + + move.x=person[i].whichblockx*block_spacing; + + move.z=person[i].whichblocky*block_spacing; + + whichtri=blockocclude.LineCheck2(camera.position,person[i].playercoords,&collpoint,move,0); + + if(whichtri!=-1)draw=0; + + } + + if(i==0)draw=1; + + } + + if(person[i].skeleton.free==1){ + + if(draw) + + if(!person[i].skeleton.broken&&!frustum.CubeInFrustum(person[i].averageloc.x,person[i].averageloc.y,person[i].averageloc.z,5))draw=0; + + if(draw) + + if(findDistancefast(person[i].averageloc,camera.position)>1000000)draw=0; + + if(draw) + + if(person[i].skeleton.joints[0].position.y<-2)draw=0; + + for(int j=beginx;j<=endx;j++){ + + for(int k=beginz;k<=endz;k++){ + + if(draw){ + + move.y=0; + + move.x=j*block_spacing; + + move.z=k*block_spacing; + + if(findDistancefast(move,camera.position)<100000){ + + whichtri=blockocclude.LineCheck2(camera.position,person[i].averageloc,&collpoint,move,0); + + if(whichtri!=-1)draw=0; + + } + + } + + } + + } + + if(draw){ + + move.y=0; + + move.x=person[i].whichblockx*block_spacing; + + move.z=person[i].whichblocky*block_spacing; + + whichtri=blockocclude.LineCheck2(camera.position,person[i].averageloc,&collpoint,move,0); + + if(whichtri!=-1)draw=0; + + } + + if(i==0)draw=1; + + } + + if(draw&&person[i].existing==1){ + + if((findDistancefast(person[i].playercoords,camera.position)<100000+zoom*3000000&&person[i].skeleton.free<1)||(findDistancefast(person[i].averageloc,camera.position)<100000+zoom*3000000&&person[i].skeleton.free>=1)){ + + glPushMatrix(); + + if(person[i].skeleton.free==0){ + + glTranslatef(person[i].playercoords.x,person[i].playercoords.y,person[i].playercoords.z); + + glRotatef(person[i].playerrotation,0,1,0); + + if(i!=0||visions==0)person[i].DoAnimations(i); + + if(i==0&&visions==1)person[i].DoAnimationslite(i); + + } + + if(visions==1)nocolors=1; + + if(visions==1&&person[i].type==eviltype)nocolors=2; + + if(visions==1&&person[i].type==viptype)nocolors=3; + + if(!(visions==1&&i==0)&&!(zoom==1&&i==0))person[i].DrawSkeleton(i); + + glPopMatrix(); + + } + + else{ + + glPushMatrix(); + + if(person[i].skeleton.free<1)person[i].DoAnimationslite(i); + + glColor4f(1,1,1,1); + + glEnable(GL_BLEND); + + glDisable(GL_CULL_FACE); + + glEnable(GL_TEXTURE_2D); + + glDisable(GL_LIGHTING); + + glDepthMask(0); + + glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + + if(person[i].skeleton.free<1){ + + glBindTexture(GL_TEXTURE_2D, personspritetextureptr); + + glTranslatef(person[i].playercoords.x,person[i].playercoords.y+size/2*.3,person[i].playercoords.z); + + } + + if(person[i].skeleton.free==1){ + + glBindTexture(GL_TEXTURE_2D, deadpersonspritetextureptr); + + glTranslatef(person[i].averageloc.x,person[i].averageloc.y+size/2*.3,person[i].averageloc.z); + + } + + glGetFloatv(GL_MODELVIEW_MATRIX,M); + + drawpoint.x=M[12]; + + drawpoint.y=M[13]; + + drawpoint.z=M[14]; + + glLoadIdentity(); + + glTranslatef(drawpoint.x, drawpoint.y, drawpoint.z); + + glBegin(GL_TRIANGLES); + + glTexCoord2f(1.0f, 1.0f); glVertex3f( .3f*size, .3f*size, 0.0f); + + glTexCoord2f(0.0f, 1.0f); glVertex3f(-.3f*size, .3f*size, 0.0f); + + glTexCoord2f(1.0f, 0.0f); glVertex3f( .3f*size,-.3f*size, 0.0f); + + glTexCoord2f(0.0f, 0.0f); glVertex3f(-.3f*size,-.3f*size, 0.0f); + + glTexCoord2f(1.0f, 0.0f); glVertex3f( .3f*size, -.3f*size, 0.0f); + + glTexCoord2f(0.0f, 1.0f); glVertex3f(-.3f*size, .3f*size, 0.0f); + + glEnd(); + + glPopMatrix(); + + glDepthMask(1); + + glDisable(GL_TEXTURE_2D); + + glEnable(GL_CULL_FACE); + + if(visions!=1)glEnable(GL_LIGHTING); + + } + + } + + if(person[i].skeleton.free<1&&!draw)person[i].DoAnimationslite(i); + + + + if(!person[i].existing) + + if(!draw||findDistancefast(person[i].playercoords,camera.position)>10000){person[i].existing=1;} + + } + + glDisable(GL_COLOR_MATERIAL); + + glDisable(GL_BLEND); + + + + //Attacker psychicness + + for(i=0;i-1&&person[i].killtargetvisible&&person[i].skeleton.free==0&&person[person[i].killtarget].skeleton.free==0){ + + sprites.MakeSprite(bulletinstant, (shotdelayamount/difficulty-person[i].shotdelay)/shotdelayamount/difficulty/2, 1, person[i].shotdelay/shotdelayamount/difficulty, person[i].shotdelay/shotdelayamount/difficulty, DoRotation(person[i].skeleton.joints[person[i].skeleton.jointlabels[lefthand]].position,0,person[i].playerrotation,0)+person[i].playercoords, person[person[i].killtarget].skeleton.joints[person[person[i].killtarget].skeleton.jointlabels[abdomen]].position+person[person[i].killtarget].playercoords, person[i].shotdelay*2); + + } + + if(person[i].killtarget>-1&&person[i].killtargetvisible&&person[i].skeleton.free==0&&person[person[i].killtarget].skeleton.free!=0){ + + sprites.MakeSprite(bulletinstant, (shotdelayamount/difficulty-person[i].shotdelay)/shotdelayamount/difficulty/2, 1, person[i].shotdelay/shotdelayamount/difficulty, person[i].shotdelay/shotdelayamount/difficulty, DoRotation(person[i].skeleton.joints[person[i].skeleton.jointlabels[lefthand]].position,0,person[i].playerrotation,0)+person[i].playercoords, person[person[i].killtarget].skeleton.joints[person[person[i].killtarget].skeleton.jointlabels[abdomen]].position, person[i].shotdelay*2); + + } + + } + + + + //Sprites + + glEnable(GL_CLIP_PLANE0); + + sprites.draw(); + + + + glDisable(GL_CLIP_PLANE0); + + + + glDisable(GL_FOG); + + //Zoom + + glAlphaFunc(GL_GREATER, 0.01); + + + + if(zoom){ + + glDisable(GL_DEPTH_TEST); // Disables Depth Testing + + glDisable(GL_CULL_FACE); + + glDisable(GL_LIGHTING); + + glDepthMask(0); + + glMatrixMode(GL_PROJECTION); // Select The Projection Matrix + + glPushMatrix(); // Store The Projection Matrix + + glLoadIdentity(); // Reset The Projection Matrix + + glOrtho(0,screenwidth,0,screenheight,-100,100); // Set Up An Ortho Screen + + glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix + + glPushMatrix(); // Store The Modelview Matrix + + glLoadIdentity(); // Reset The Modelview Matrix + + glScalef(screenwidth,screenheight,1); + + glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + + glEnable(GL_BLEND); + + glEnable(GL_TEXTURE_2D); + + glColor4f(.5,.5,.5,1); + + glBindTexture(GL_TEXTURE_2D, scopetextureptr); + + glBegin(GL_QUADS); + + glTexCoord2f(0,0); + + glVertex3f(0, 0, 0.0f); + + glTexCoord2f(1,0); + + glVertex3f(1, 0, 0.0f); + + glTexCoord2f(1,1); + + glVertex3f(1, 1, 0.0f); + + glTexCoord2f(0,1); + + glVertex3f(0, 1, 0.0f); + + glEnd(); + + glDisable(GL_TEXTURE_2D); + + glMatrixMode(GL_PROJECTION); // Select The Projection Matrix + + glPopMatrix(); // Restore The Old Projection Matrix + + glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix + + glPopMatrix(); // Restore The Old Projection Matrix + + glEnable(GL_DEPTH_TEST); // Enables Depth Testing + + glEnable(GL_CULL_FACE); + + glDisable(GL_BLEND); + + glDepthMask(1); + + } + + + + //Flash + + if(flashamount>0){ + + if(flashamount>1)flashamount=1; + + flashamount-=multiplier; + + if(flashamount<0)flashamount=0; + + glDisable(GL_DEPTH_TEST); // Disables Depth Testing + + glDisable(GL_CULL_FACE); + + glDisable(GL_LIGHTING); + + glDepthMask(0); + + glMatrixMode(GL_PROJECTION); // Select The Projection Matrix + + glPushMatrix(); // Store The Projection Matrix + + glLoadIdentity(); // Reset The Projection Matrix + + glOrtho(0,screenwidth,0,screenheight,-100,100); // Set Up An Ortho Screen + + glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix + + glPushMatrix(); // Store The Modelview Matrix + + glLoadIdentity(); // Reset The Modelview Matrix + + glScalef(screenwidth,screenheight,1); + + glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + + glEnable(GL_BLEND); + + glColor4f(flashr,flashg,flashb,flashamount); + + glBegin(GL_QUADS); + + glVertex3f(0, 0, 0.0f); + + glVertex3f(256, 0, 0.0f); + + glVertex3f(256, 256, 0.0f); + + glVertex3f(0, 256, 0.0f); + + glEnd(); + + glMatrixMode(GL_PROJECTION); // Select The Projection Matrix + + glPopMatrix(); // Restore The Old Projection Matrix + + glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix + + glPopMatrix(); // Restore The Old Projection Matrix + + glEnable(GL_DEPTH_TEST); // Enables Depth Testing + + glEnable(GL_CULL_FACE); + + glDisable(GL_BLEND); + + glDepthMask(1); + + } + + if(person[0].skeleton.free>0&&thirdperson!=2){ + + glDisable(GL_DEPTH_TEST); // Disables Depth Testing + + glDisable(GL_CULL_FACE); + + glDisable(GL_LIGHTING); + + glDepthMask(0); + + glMatrixMode(GL_PROJECTION); // Select The Projection Matrix + + glPushMatrix(); // Store The Projection Matrix + + glLoadIdentity(); // Reset The Projection Matrix + + glOrtho(0,screenwidth,0,screenheight,-100,100); // Set Up An Ortho Screen + + glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix + + glPushMatrix(); // Store The Modelview Matrix + + glLoadIdentity(); // Reset The Modelview Matrix + + glScalef(screenwidth,screenheight,1); + + glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + + glEnable(GL_BLEND); + + glColor4f(0,0,0,1-person[0].longdead); + + glBegin(GL_QUADS); + + glVertex3f(0, 0, 0.0f); + + glVertex3f(256, 0, 0.0f); + + glVertex3f(256, 256, 0.0f); + + glVertex3f(0, 256, 0.0f); + + glEnd(); + + glMatrixMode(GL_PROJECTION); // Select The Projection Matrix + + glPopMatrix(); // Restore The Old Projection Matrix + + glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix + + glPopMatrix(); // Restore The Old Projection Matrix + + glEnable(GL_DEPTH_TEST); // Enables Depth Testing + + glEnable(GL_CULL_FACE); + + glDisable(GL_BLEND); + + glDepthMask(1); + + } + + + + //Text + + glEnable(GL_TEXTURE_2D); + + glColor4f(1,1,1,1); + + static char string[256]=""; + + if(!debug){ + + if(person[0].whichgun==nogun)sprintf (string, "UNARMED"); + + if(person[0].whichgun==knife)sprintf (string, "KNIFE"); + + if(person[0].whichgun==assaultrifle)sprintf (string, "ASSAULT RIFLE"); + + if(person[0].whichgun==shotgun)sprintf (string, "SHOTGUN"); + + if(person[0].whichgun==sniperrifle)sprintf (string, "SNIPER RIFLE"); + + if(person[0].whichgun==grenade)sprintf (string, "HAND GRENADE"); + + if(person[0].whichgun==handgun1)sprintf (string, "MAGNUM"); + + if(person[0].whichgun==handgun2)sprintf (string, "HANDGUN"); + + text.glPrint(10,90,string,1,.8,640,480); + + if(person[0].whichgun!=nogun&&person[0].whichgun!=knife&&person[0].whichgun!=grenade){ + + glColor4f(0,1,0,1); + + sprintf (string, "Magazines"); + + text.glPrint(10,30,string,0,.8,640,480); + + glColor4f(1,1,1,1); + + sprintf (string, "0%d",(int)person[0].reloads[person[0].whichgun]); + + text.glPrint(10,10,string,1,1,640,480); + + if(person[0].ammo>=0){ + + glColor4f(0,1,0,1); + + sprintf (string, "Ammo"); + + text.glPrint(10,65,string,0,.8,640,480); + + glColor4f(1,1,1,1); + + if(person[0].ammo>=10)sprintf (string, "%d",(int)person[0].ammo); + + if(person[0].ammo<10)sprintf (string, "0%d",(int)person[0].ammo); + + text.glPrint(10,40,string,1,1,640,480); + + } + + } + + if(person[0].whichgun==grenade){ + + sprintf (string, "Grenades Left: %d",(int)person[0].reloads[person[0].whichgun]+1); + + text.glPrint(10,20,string,0,.8,640,480); + + } + + glColor4f(1,1,0,1); + + sprintf (string, "Score"); + + text.glPrint(725,575,string,0,.8,640,480); + + glColor4f(1,1,1,1); + + sprintf (string, "%d", score); + + text.glPrint(580,440,string,1,1,640,480); + + + + glColor4f(1,1,0,1); + + sprintf (string, "Time Remaining"); + + text.glPrint(50,575,string,0,.8,640,480); + + glColor4f(1,1,1,1); + + if((int)timeremaining%60>=10)sprintf (string, "%d:%d", (int)(timeremaining/60),(int)timeremaining%60); + + if((int)timeremaining%60<10)sprintf (string, "%d:0%d", (int)(timeremaining/60),(int)timeremaining%60); + + text.glPrint(72.5,440,string,1,1,640,480); + + } + + + + if(debug){ + + sprintf (string, "The framespersecond is %d out of maximum %d.",(int)framespersecond+1,maxfps); + + text.glPrint(10,30,string,0,.8,screenwidth,screenheight); + + if(enemystate==0)sprintf (string, "Enemies are in random assassination mode."); + + if(enemystate==1)sprintf (string, "Enemies are in passive mode."); + + if(enemystate==2)sprintf (string, "Enemies are in DIE!!!! mode."); + + text.glPrint(10,20,string,0,.8,screenwidth,screenheight); + + sprintf (string, "You have pointlessly shot or beaten %d unarmed civilians.",civkills); + + text.glPrint(10,60,string,0,.8,screenwidth,screenheight); + + sprintf (string, "You have incapacitated %d assassins.",goodkills); + + text.glPrint(10,70,string,0,.8,screenwidth,screenheight); + + sprintf (string, "You have allowed %d successful murders.",badkills); + + text.glPrint(10,80,string,0,.8,screenwidth,screenheight); + + } + + /* + sprintf (string, ""); + + text.glPrint(10,80,string,0,.8,screenwidth,screenheight); + */ + + } + + return 1; +} + diff --git a/blackshades_revenge/Source/GameInitDispose.cpp b/blackshades_revenge/Source/GameInitDispose.cpp new file mode 100644 index 0000000..c072c73 --- /dev/null +++ b/blackshades_revenge/Source/GameInitDispose.cpp @@ -0,0 +1,3929 @@ +#include + +#ifndef OS9 +#include +#endif + +#include "Game.h" + +#include "SoundFX.h" + +#include + +extern unsigned int gSourceID[100]; + +extern unsigned int gSampleSet[100]; + +extern Camera camera; + +extern Skeleton testskeleton; + +extern Sprites sprites; + +extern Decals decals; + +/*********************> InitGame()<*****/ + +extern Model skeletonmodels[10]; + +extern Model gunmodels[10]; + +extern Costume costume[10]; + +extern Animation animation[30]; + +extern int visions; + +extern float rad2deg; + +extern Fog fog; + +extern bool blood; + +extern float fogcolorr; + +extern float fogcolorg; + +extern float fogcolorb; + +extern int environment; + +extern float precipitationhorz; + +extern float precipitationvert; + +extern float precipitationdensity; + +extern float soundscalefactor; + +extern int slomo; + + + +extern int forwardskey; + +extern int backwardskey; + +extern int leftkey; + +extern int rightkey; + +extern int aimkey; + +extern int psychicaimkey; + +extern int psychickey; + + + +void LoadSounds(bool musictoggle); + +void LoadSounds(bool musictoggle) + +{ + char *pBuffer1; + + long lBuffer1Len; + + ALenum formatBuffer1; + + ALsizei freqBuffer1; + + + // initialize OpenAL + alutInit(NULL, 0); + + // prime the singleton + SoundFX::inst(); + + + + SInt16 iNumSampleSets; + iNumSampleSets = 37; + ALint error; + + alGenBuffers(iNumSampleSets, &gSampleSet[0]); + if ((error = alGetError()) != AL_NO_ERROR) + { + // got error + } + +#ifdef NOOGG + alutLoadWAVFile_CFH((char *)":Data:Sounds:underwater.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[visionsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:soulin.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[soulinsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:soulout.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[souloutsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:footstep1.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[footstepsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:footstep2.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[footstepsound+1], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:footstep3.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[footstepsound+2], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:footstep4.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[footstepsound+3], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:footstep5.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[footstepsound+4], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:bodyland.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alSourcei(gSourceID[src_bodylandsound], AL_BUFFER, gSampleSet[bodylandsound]); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:headland.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[headlandsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:sniperrifle.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[riflesound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:BodyHit.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[bodyhitsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:WallHit.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[wallhitsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:machinegun.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[machinegunsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:Nearbullet.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[nearbulletsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:riflewhack.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[headwhacksound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:headshot.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[headshotsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:reload.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[reloadsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:click.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[clicksound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:SW.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[pistol1sound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:glock.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[pistol2sound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:pinpull.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[pinpullsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:pinreplace.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[pinreplacesound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:handlerelease.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[grenadethrowsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:bounce.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[bouncesound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:bounce2.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[bounce2sound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:explosion.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[explosionsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:headland.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[bodywhacksound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:rain.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[rainsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:Lose.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[losesound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:Disguisekill.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[disguisekillsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:knifeslash.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[knifeslashsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:shotgun.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[shotgunsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + if(musictoggle) + { + alutLoadWAVFile_CFH((char *)":Data:Sounds:mainmenusong.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[mainmenusong], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:shootsong.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[shootsong], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:zombiesong.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[zombiesong], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + alutLoadWAVFile_CFH((char *)":Data:Sounds:knifesong.wav",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[knifesong], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + alutUnloadWAV(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + } +#else + LoadOGG_CFH((char *)":Data:Sounds:underwater.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[visionsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:soulin.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[soulinsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:soulout.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[souloutsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:footstep1.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[footstepsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:footstep2.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[footstepsound+1], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:footstep3.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[footstepsound+2], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:footstep4.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[footstepsound+3], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:footstep5.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[footstepsound+4], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:bodyland.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[bodylandsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:headland.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[headlandsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:sniperrifle.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[riflesound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:BodyHit.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[bodyhitsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:WallHit.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[wallhitsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:machinegun.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[machinegunsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:Nearbullet.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[nearbulletsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:riflewhack.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[headwhacksound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:headshot.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[headshotsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:reload.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[reloadsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:click.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[clicksound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:SW.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + + alBufferData(gSampleSet[pistol1sound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:glock.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + + alBufferData(gSampleSet[pistol2sound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:pinpull.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + + alBufferData(gSampleSet[pinpullsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:pinreplace.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + + alBufferData(gSampleSet[pinreplacesound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:handlerelease.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[grenadethrowsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:bounce.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[bouncesound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:bounce2.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[bounce2sound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:explosion.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[explosionsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:headland.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[bodywhacksound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:rain.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[rainsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:Lose.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[losesound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:Disguisekill.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[disguisekillsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:knifeslash.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[knifeslashsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:shotgun.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[shotgunsound], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + if(musictoggle) + { + LoadOGG_CFH((char *)":Data:Sounds:mainmenusong.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[mainmenusong], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:shootsong.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[shootsong], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:zombiesong.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[zombiesong], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + + + + LoadOGG_CFH((char *)":Data:Sounds:knifesong.ogg",&formatBuffer1, (void **) &pBuffer1,(unsigned int *)&lBuffer1Len,&freqBuffer1); + alBufferData(gSampleSet[knifesong], formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + FreeOGG(formatBuffer1, pBuffer1, lBuffer1Len, freqBuffer1); + } + + +#endif + + // need to carry some of this over, see notes. +/* + float gLoc[3]; + + + + gLoc[0]=0; + + gLoc[1]=0; + + gLoc[2]=0; + + + alSourcefv(gSourceID[src_visionsound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_visionsound], AL_LOOPING, 1); + + alSourcef(gSourceID[src_visionsound], AL_MIN_GAIN, 1); + + + + alSourcefv(gSourceID[src_soulinsound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_soulinsound], AL_LOOPING, 0); + + alSourcef(gSourceID[src_soulinsound], AL_MIN_GAIN, 1); + + + + alSourcefv(gSourceID[src_souloutsound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_souloutsound], AL_LOOPING, 0); + + alSourcef(gSourceID[src_souloutsound], AL_MIN_GAIN, 1); + + + + for(int i=0;i<5;i++){ + + //alSourcei(gSourceID[src_footstepsound], AL_BUFFER, gSampleSet[footstepsound]); + alSourcefv(gSourceID[src_footstepsound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_footstepsound], AL_LOOPING, 0); + + alSourcef(gSourceID[src_footstepsound], AL_MIN_GAIN, 0); + + } + + + + alSourcefv(gSourceID[src_bodylandsound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_bodylandsound], AL_LOOPING, 0); + + alSourcef(gSourceID[src_bodylandsound], AL_MIN_GAIN, 0); + + + + alSourcefv(gSourceID[src_headlandsound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_headlandsound], AL_LOOPING, 0); + + alSourcef(gSourceID[src_headlandsound], AL_MIN_GAIN, 0); + + + + alSourcefv(gSourceID[src_riflesound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_riflesound], AL_LOOPING, 0); + + alSourcef(gSourceID[src_riflesound], AL_MIN_GAIN, 0); + + + + alSourcefv(gSourceID[src_bodyhitsound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_bodyhitsound], AL_LOOPING, 0); + + alSourcef(gSourceID[src_bodyhitsound], AL_MIN_GAIN, .1); + + + + alSourcefv(gSourceID[src_wallhitsound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_wallhitsound], AL_LOOPING, 0); + + alSourcef(gSourceID[src_wallhitsound], AL_MIN_GAIN, 0); + + alSourcef(gSourceID[src_wallhitsound], AL_MAX_GAIN, .6); + + + + alSourcefv(gSourceID[src_machinegunsound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_machinegunsound], AL_LOOPING, 0); + + alSourcef(gSourceID[src_machinegunsound], AL_MIN_GAIN,0); + + + + alSourcefv(gSourceID[src_nearbulletsound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_nearbulletsound], AL_LOOPING, 0); + + alSourcef(gSourceID[src_nearbulletsound], AL_MIN_GAIN,0); + + + + alSourcefv(gSourceID[src_headwhacksound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_headwhacksound], AL_LOOPING, 0); + + alSourcef(gSourceID[src_headwhacksound], AL_MIN_GAIN,0); + + + + alSourcefv(gSourceID[src_headshotsound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_headshotsound], AL_LOOPING, 0); + + alSourcef(gSourceID[src_headshotsound], AL_MIN_GAIN, 0); + + + + alSourcefv(gSourceID[src_reloadsound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_reloadsound], AL_LOOPING, 0); + + alSourcef(gSourceID[src_reloadsound], AL_MIN_GAIN, 0); + + + + alSourcefv(gSourceID[src_clicksound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_clicksound], AL_LOOPING, 0); + + alSourcef(gSourceID[src_clicksound], AL_MIN_GAIN, 0); + + + + alSourcefv(gSourceID[src_pistol1sound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_pistol1sound], AL_LOOPING, 0); + + alSourcef(gSourceID[src_pistol1sound], AL_MIN_GAIN, 0); + + + + alSourcefv(gSourceID[src_pistol2sound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_pistol2sound], AL_LOOPING, 0); + + alSourcef(gSourceID[src_pistol2sound], AL_MIN_GAIN, 0); + + + + alSourcefv(gSourceID[src_pinpullsound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_pinpullsound], AL_LOOPING, 0); + + alSourcef(gSourceID[src_pinpullsound], AL_MIN_GAIN,0); + + + + alSourcefv(gSourceID[src_pinreplacesound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_pinreplacesound], AL_LOOPING, 0); + + alSourcef(gSourceID[src_pinreplacesound], AL_MIN_GAIN,0); + + + + alSourcefv(gSourceID[src_grenadethrowsound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_grenadethrowsound], AL_LOOPING, 0); + + alSourcef(gSourceID[src_grenadethrowsound], AL_MIN_GAIN,0); + + + + alSourcefv(gSourceID[src_bouncesound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_bouncesound], AL_LOOPING, 0); + + alSourcef(gSourceID[src_bouncesound], AL_MIN_GAIN,0); + + + + alSourcefv(gSourceID[src_bounce2sound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_bounce2sound], AL_LOOPING, 0); + + alSourcef(gSourceID[src_bounce2sound], AL_MIN_GAIN,0); + + + + alSourcefv(gSourceID[src_explosionsound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_explosionsound], AL_LOOPING, 0); + + alSourcef(gSourceID[src_explosionsound], AL_MIN_GAIN,0); + + + + alSourcefv(gSourceID[src_bodywhacksound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_bodywhacksound], AL_LOOPING, 0); + + alSourcef(gSourceID[src_bodywhacksound], AL_MIN_GAIN, 0); + + + + alSourcefv(gSourceID[src_rainsound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_rainsound], AL_LOOPING, 1); + + alSourcef(gSourceID[src_rainsound], AL_MIN_GAIN, .3); + + + + alSourcefv(gSourceID[src_losesound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_losesound], AL_LOOPING, 0); + + alSourcef(gSourceID[src_losesound], AL_MIN_GAIN, 1); + + + + alSourcefv(gSourceID[src_disguisekillsound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_disguisekillsound], AL_LOOPING, 0); + + alSourcef(gSourceID[src_disguisekillsound], AL_MIN_GAIN, 1); + + + + alSourcefv(gSourceID[src_knifeslashsound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_knifeslashsound], AL_LOOPING, 0); + + alSourcef(gSourceID[src_knifeslashsound], AL_MIN_GAIN,0); + + + + alSourcefv(gSourceID[src_shotgunsound], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_shotgunsound], AL_LOOPING, 0); + + alSourcef(gSourceID[src_shotgunsound], AL_MIN_GAIN, 0); + + + + alSourcefv(gSourceID[src_knifesong], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_knifesong], AL_LOOPING, 1); + + alSourcef(gSourceID[src_knifesong], AL_MIN_GAIN, 1); + + + + alSourcefv(gSourceID[src_mainmenusong], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_mainmenusong], AL_LOOPING, 1); + + alSourcef(gSourceID[src_mainmenusong], AL_MIN_GAIN, 1); + + + + alSourcefv(gSourceID[src_zombiesong], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_zombiesong], AL_LOOPING, 1); + + alSourcef(gSourceID[src_zombiesong], AL_MIN_GAIN, 1); + + + + alSourcefv(gSourceID[src_shootsong], AL_POSITION, gLoc); + + alSourcei(gSourceID[src_shootsong], AL_LOOPING, 1); + + alSourcef(gSourceID[src_shootsong], AL_MIN_GAIN, 1); +*/ + + + + +} + + + +void Game::LoadingScreen(float percent) + +{ + + float size=1; + + glLoadIdentity(); + + //Clear to black + + glClearColor(0,0,0,1); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + + + //Background + + + + glDisable(GL_TEXTURE_2D); + + glDisable(GL_DEPTH_TEST); // Disables Depth Testing + + glDisable(GL_CULL_FACE); + + glDisable(GL_LIGHTING); + + glDepthMask(0); + + glMatrixMode(GL_PROJECTION); // Select The Projection Matrix + + glPushMatrix(); // Store The Projection Matrix + + glLoadIdentity(); // Reset The Projection Matrix + + glOrtho(0,640,0,480,-100,100); // Set Up An Ortho Screen + + glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix + + glPushMatrix(); // Store The Modelview Matrix + + for(int i=19;i>=0;i--){ + + glLoadIdentity(); // Reset The Modelview Matrix + + glTranslatef(120-i*1,190-i*1,0); + + glScalef(400+i*2,30+i*2,1); + + glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + + glEnable(GL_BLEND); + + if(i)glColor4f(1-(float)i/20-percent/100,1-(float)i/20-percent/100,1-(float)i/20-percent/100,1); + + if(!i)glColor4f(0,0,0,1); + + glBegin(GL_QUADS); + + glVertex3f(0, 0, 0.0f); + + glVertex3f(1, 0, 0.0f); + + glVertex3f(1, 1, 0.0f); + + glVertex3f(0, 1, 0.0f); + + glEnd(); + + } + + glMatrixMode(GL_PROJECTION); // Select The Projection Matrix + + glPopMatrix(); // Restore The Old Projection Matrix + + glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix + + glPopMatrix(); // Restore The Old Projection Matrix + + glDisable(GL_BLEND); + + glDepthMask(1); + + + + //Progress + + + + glDisable(GL_DEPTH_TEST); // Disables Depth Testing + + glDisable(GL_CULL_FACE); + + glDisable(GL_LIGHTING); + + glDisable(GL_TEXTURE_2D); + + glDepthMask(0); + + glMatrixMode(GL_PROJECTION); // Select The Projection Matrix + + glPushMatrix(); // Store The Projection Matrix + + glLoadIdentity(); // Reset The Projection Matrix + + glOrtho(0,640,0,480,-100,100); // Set Up An Ortho Screen + + glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix + + glPushMatrix(); // Store The Modelview Matrix + + for(i=19;i>=0;i--){ + + glLoadIdentity(); // Reset The Modelview Matrix + + glTranslatef(120,190,0); + + if(4*percent+i*2<400)glScalef(4*percent+i*2,30,1); + + if(4*percent+i*2>=400)glScalef(400,30,1); + + glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + + glEnable(GL_BLEND); + + glColor4f(1,0,0,.1); + + glBegin(GL_QUADS); + + glVertex3f(0, 0, 0.0f); + + glVertex3f(1, 0, 0.0f); + + glVertex3f(1, 1, 0.0f); + + glVertex3f(0, 1, 0.0f); + + glEnd(); + + } + + glMatrixMode(GL_PROJECTION); // Select The Projection Matrix + + glPopMatrix(); // Restore The Old Projection Matrix + + glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix + + glPopMatrix(); // Restore The Old Projection Matrix + + glDisable(GL_BLEND); + + glDepthMask(1); + + + + //Text + + + + glEnable(GL_TEXTURE_2D); + + glColor4f(.6-.6*percent/100,0,0,1); + + static char string[256]=""; + + sprintf (string, "LOADING..."); + + text.glPrint(280,195,string,1,1,640,480); + + + + +#ifdef OS9 + aglSwapBuffers( gOpenGLContext ); +#else + SDL_GL_SwapBuffers( ); +#endif + +} + + + +void LoadPersonSpriteTexture(char *fileName, GLuint *textureid); + +void LoadPersonSpriteTexture(char *fileName, GLuint *textureid) + +{ + + TGAImageRec *tempTexture; + + GLuint type; + + + + //Load Image + + tempTexture = LoadTGA( fileName ); + + //Is it valid? + + if(tempTexture){ + + //Alpha channel? + + if ( tempTexture->bpp == 24 ) + + type = GL_RGB; + + else + + type = GL_RGBA; + + + + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + + + + glGenTextures( 1, textureid ); + + glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + + + + glBindTexture( GL_TEXTURE_2D, *textureid); + + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + + + + gluBuild2DMipmaps( GL_TEXTURE_2D, type, tempTexture->sizeX, tempTexture->sizeY, type, GL_UNSIGNED_BYTE, tempTexture->data ); + + free( tempTexture->data ); + + free( tempTexture ); + + } + +} + + + +void Game::InitGame() + +{ + + //Setup loading screen + + float loadingscreenamount=0; + + float loadingscreenamounttotal=200; + + if(initialized)loadingscreenamounttotal=20; + + + + if(!initialized)LoadingScreen(loadingscreenamount/loadingscreenamounttotal*100); + + + + //Set up rain and snow + + precipitationhorz=60; + + precipitationvert=40; + + precipitationdensity=25; + + + + //Bodyguard stats + + person[0].health=100; + + person[0].targetanimation=idleanim; + + person[0].targetframe=0; + + person[0].playercoords=camera.position; + + person[0].oldplayercoords=person[0].playercoords; + + person[0].type=playertype; + + person[0].existing=1; + + for(int i=0;i<10;i++){ + + person[0].reloads[i]=0; + + } + + + + //Level setup + + killedinnocent=0; //Haven't shot any civilians yet... + + + + if(customlevels){ //Load custom levels + + nummissions=1; //Default level in case of load failure + + type=randomshoot_type; + + possiblegun[0]=handgun1; + + possiblegun[1]=handgun2; + + possiblegun[2]=shotgun; + + numpossibleguns=3; + + evilprobability=6; + + person[0].whichgun=knife; + + person[0].reloads[person[0].whichgun]=6; + + if(!gameinprogress)score=0; + + timeremaining=50; + + difficulty=.8; + + std::ifstream ipstream("Data/customlevels.txt"); + + if(!ipstream) { + + customlevels=0; + + } + + if(ipstream){ + + ipstream.ignore(256,'\n');//ignore descriptive text + + ipstream >> nummissions; + + for(int j=0;j> type; + + ipstream.ignore(256,'\n'); + + ipstream.ignore(256,'\n'); + + ipstream >> environment; + + ipstream.ignore(256,'\n'); + + ipstream.ignore(256,'\n'); + + ipstream >> numpossibleguns; + + ipstream.ignore(256,'\n'); + + ipstream.ignore(256,'\n'); + + for(int i=0;i> possiblegun[i]; + + } + + ipstream.ignore(256,'\n'); + + ipstream.ignore(256,'\n'); + + ipstream >> evilprobability; + + ipstream.ignore(256,'\n'); + + ipstream.ignore(256,'\n'); + + ipstream >> person[0].whichgun; + + ipstream.ignore(256,'\n'); + + ipstream.ignore(256,'\n'); + + ipstream >> person[0].reloads[person[0].whichgun]; + + ipstream.ignore(256,'\n'); + + ipstream.ignore(256,'\n'); + + ipstream >> timeremaining; + + ipstream.ignore(256,'\n'); + + ipstream.ignore(256,'\n'); + + ipstream >> difficulty; + + ipstream.ignore(256,'\n'); + + } + + ipstream.close(); + + } + + } + + + + if(!customlevels){ //Setup hardcoded default levels + + if(mission==0){ + + environment=sunny_environment; + + type=randomshoot_type; + + possiblegun[0]=handgun1; + + possiblegun[1]=handgun2; + + possiblegun[2]=shotgun; + + numpossibleguns=3; + + evilprobability=6; + + person[0].whichgun=assaultrifle; + + person[0].reloads[person[0].whichgun]=6; + + if(!gameinprogress)score=0; + + timeremaining=50; + + difficulty=.6; + + } + + if(mission==1){ + + environment=snowy_environment; + + type=randomshoot_type; + + possiblegun[0]=knife; + + possiblegun[1]=assaultrifle; + + numpossibleguns=2; + + evilprobability=5; + + person[0].whichgun=handgun2; + + person[0].reloads[person[0].whichgun]=3; + + if(!gameinprogress)score=0; + + timeremaining=40; + + difficulty=.6; + + } + + if(mission==2){ + + environment=foggy_environment; + + type=randomshoot_type; + + possiblegun[0]=sniperrifle; + + numpossibleguns=1; + + evilprobability=5; + + person[0].whichgun=sniperrifle; + + person[0].reloads[person[0].whichgun]=4; + + if(!gameinprogress)score=0; + + timeremaining=50; + + difficulty=0.9; + + } + + if(mission==3){ + + environment=firey_environment; + + type=zombie_type; + + numpossibleguns=0; + + evilprobability=5; + + person[0].whichgun=shotgun; + + person[0].reloads[person[0].whichgun]=5; + + if(!gameinprogress)score=0; + + timeremaining=35; + + difficulty=.7; + + } + + if(mission==4){ + + environment=snowy_environment; + + type=randomshoot_type; + + possiblegun[0]=sniperrifle; + + possiblegun[1]=assaultrifle; + + numpossibleguns=2; + + evilprobability=5; + + person[0].whichgun=grenade; + + person[0].reloads[person[0].whichgun]=20; + + if(!gameinprogress)score=0; + + timeremaining=30; + + difficulty=.5; + + } + + if(mission==5){ + + environment=rainy_environment; + + type=randomshoot_type; + + possiblegun[0]=handgun1; + + possiblegun[1]=shotgun; + + possiblegun[2]=assaultrifle; + + numpossibleguns=3; + + evilprobability=6; + + person[0].whichgun=knife; + + person[0].reloads[person[0].whichgun]=3; + + if(!gameinprogress)score=0; + + timeremaining=40; + + difficulty=.8; + + } + + if(mission==6){ + + environment=night_environment; + + type=randomshoot_type; + + possiblegun[1]=handgun1; + + possiblegun[2]=handgun2; + + possiblegun[3]=shotgun; + + numpossibleguns=3; + + evilprobability=5; + + person[0].whichgun=handgun1; + + person[0].reloads[person[0].whichgun]=4; + + if(!gameinprogress)score=0; + + timeremaining=30; + + difficulty=1; + + } + + if(mission==7){ + + environment=firey_environment; + + type=zombie_type; + + person[0].whichgun=assaultrifle; + + person[0].reloads[person[0].whichgun]=5; + + if(!gameinprogress)score=0; + + timeremaining=30; + + difficulty=1; + + } + + if(mission==8){ + + environment=rainy_environment; + + type=randomshoot_type; + + possiblegun[0]=handgun1; + + possiblegun[1]=handgun2; + + possiblegun[2]=shotgun; + + possiblegun[3]=sniperrifle; + + possiblegun[4]=assaultrifle; + + numpossibleguns=5; + + evilprobability=5; + + person[0].whichgun=nogun; + + person[0].reloads[person[0].whichgun]=3; + + if(!gameinprogress)score=0; + + timeremaining=40; + + difficulty=.8; + + } + + if(mission==9){ + + environment=snowy_environment; + + type=randomshoot_type; + + possiblegun[0]=knife; + + possiblegun[1]=handgun1; + + possiblegun[2]=handgun2; + + possiblegun[3]=shotgun; + + possiblegun[4]=sniperrifle; + + possiblegun[5]=assaultrifle; + + numpossibleguns=6; + + evilprobability=4; + + person[0].whichgun=handgun1; + + person[0].reloads[person[0].whichgun]=3; + + if(!gameinprogress)score=0; + + timeremaining=90; + + difficulty=1; + + } + + if(mission==10){ + + environment=night_environment; + + type=randomshoot_type; + + possiblegun[0]=sniperrifle; + + numpossibleguns=1; + + evilprobability=5; + + person[0].whichgun=sniperrifle; + + person[0].reloads[person[0].whichgun]=4; + + if(!gameinprogress)score=0; + + timeremaining=30; + + difficulty=1.3; + + } + + if(mission==11){ + + environment=sunny_environment; + + type=randomshoot_type; + + possiblegun[0]=knife; + + possiblegun[1]=sniperrifle; + + numpossibleguns=2; + + evilprobability=4; + + person[0].whichgun=knife; + + if(!gameinprogress)score=0; + + timeremaining=30; + + difficulty=1.5; + + } + + if(mission==12){ + + environment=firey_environment; + + type=zombie_type; + + possiblegun[0]=knife; + + possiblegun[1]=sniperrifle; + + person[0].whichgun=handgun2; + + person[0].reloads[person[0].whichgun]=10; + + if(!gameinprogress)score=0; + + timeremaining=60; + + difficulty=1.5; + + } + + + + nummissions=13; + + } + + + + //Setup fast radian to degree conversion + + rad2deg= 56.54866776; + + visions=0; + + + + //Setup bounding cylinder model + + float boundingscale=3; + + + + if(!initialized){ + + boundingpoints[0]=0; + + boundingpoints[0].z=boundingscale; + + boundingpoints[0].y=0; + + for(int i=1;i<8;i++){ + + boundingpoints[i]=DoRotation(boundingpoints[0],0,i*360/7,0); + + } + + } + + civkills=0; + + badkills=0; + + goodkills=0; + + enemystate=2; + + + + if(!initialized){ + + if(!azertykeyboard){ + + forwardskey=MAC_W_KEY; + + backwardskey=MAC_S_KEY; + + leftkey=MAC_A_KEY; + + rightkey=MAC_D_KEY; + + aimkey=MAC_Q_KEY; + + psychicaimkey=MAC_E_KEY; + + psychickey=MAC_Z_KEY; + + } + + + + if(azertykeyboard){ + + forwardskey=MAC_Z_KEY; + + backwardskey=MAC_S_KEY; + + leftkey=MAC_Q_KEY; + + rightkey=MAC_D_KEY; + + aimkey=MAC_A_KEY; + + psychicaimkey=MAC_E_KEY; + + psychickey=MAC_W_KEY; + + } + + + + soundscalefactor=soundscalefactordefault; //Setup sound falloff + + + + gQuit=false; + + + + //Sounds + + LoadSounds(musictoggle); + + //Play correct song + + ALuint enviro = SoundFX::inst()->getEnviroSource(gSampleSet[rainsound]); + + alSourcef(enviro, AL_MIN_GAIN, .3); + + if(environment==rainy_environment)alSourcePlay(enviro); + + if(environment!=rainy_environment)alSourcePause(enviro); + + + if(musictoggle) + { + whichsong=mainmenusong; + + ALuint music = SoundFX::inst()->getMusicSource(gSampleSet[whichsong]); + + //redundant! + alSourcei(music, AL_BUFFER, gSampleSet[whichsong]); + alSourcef(music, AL_PITCH, 1); + alSourcef(music, AL_MIN_GAIN, 1); + alSourcef(music, AL_MAX_GAIN, 1); + alSourcePlay(music); + } + } + + + + loadingscreenamount+=5; + + if(!initialized)LoadingScreen(loadingscreenamount/loadingscreenamounttotal*100); + + + + //Setup random seed + +#ifdef OS9 + qd.randSeed = TickCount(); +#else + srand(time(NULL)); +#endif + + gamespeed=1; + + + + //Setup camera + + camera.position=0; + + camera.position.x=num_blocks/2*block_spacing+block_spacing/2; + + camera.position.z=num_blocks/2*block_spacing+block_spacing/2; + + camera.position.y=30; + + camera.oldposition=camera.position; + + numpeople=1; + + + + //Setup path to walk around blocks + + path.load((unsigned char *)":Data:Models:path.solid"); + + path.Rotate(90,0,0); + + path.Scale(.8,.8,.8); + + path.CalculateNormals(); + + + + loadingscreenamount+=5; + + if(!initialized)LoadingScreen(loadingscreenamount/loadingscreenamounttotal*100); + + + + person[0].speedmult=1.3; + + //teleport player + + person[0].whichblockx=((block_spacing/2)/block_spacing); + + person[0].whichblocky=((block_spacing/2)/block_spacing); + + person[0].pathnum=-1; + + person[0].oldpathnum=-1; + + person[0].oldoldpathnum=-1; + + person[0].oldoldoldpathnum=-1; + + while(person[0].pathnum<0||person[0].pathnum>=path.vertexNum||person[0].pathnum==1){ + + person[0].pathnum=Random()%path.vertexNum; + + } + + person[0].pathtarget.x=path.vertex[person[0].pathnum].x; + + person[0].pathtarget.z=path.vertex[person[0].pathnum].z; + + person[0].pathsize=.98+float(abs(Random()%20))/400; + + person[0].pathtarget*=person[0].pathsize; + + person[0].pathtarget.x+=person[0].whichblockx*block_spacing; + + person[0].pathtarget.z+=person[0].whichblocky*block_spacing; + + person[0].playercoords=person[0].pathtarget; + + person[0].oldplayercoords=person[0].playercoords; + + //Setup block models + + if(!initialized){ + + blocks[0].load((unsigned char *)":Data:Models:Block1.solid"); + + blocks[0].Rotate(90,0,0); + + blocks[0].Scale(.8,.8,.8); + + blocks[0].CalculateNormals(); + + + + blocks[1].load((unsigned char *)":Data:Models:Block2.solid"); + + blocks[1].Rotate(90,0,0); + + blocks[1].Scale(.8,.8,.8); + + blocks[1].CalculateNormals(); + + + + loadingscreenamount+=5; + + if(!initialized)LoadingScreen(loadingscreenamount/loadingscreenamounttotal*100); + + + + blocks[2].load((unsigned char *)":Data:Models:Block3.solid"); + + blocks[2].Rotate(90,0,0); + + blocks[2].Scale(.8,.8,.8); + + blocks[2].CalculateNormals(); + + + + blocks[3].load((unsigned char *)":Data:Models:Block4.solid"); + + blocks[3].Rotate(90,0,0); + + blocks[3].Scale(.8,.8,.8); + + blocks[3].CalculateNormals(); + + + + loadingscreenamount+=5; + + if(!initialized)LoadingScreen(loadingscreenamount/loadingscreenamounttotal*100); + + + + sidewalkcollide.load((unsigned char *)":Data:Models:Lowheightcollide.solid"); + + sidewalkcollide.Rotate(90,0,0); + + sidewalkcollide.Scale(.8,.8,.8); + + sidewalkcollide.CalculateNormals(); + + + + blockwalls[0].load((unsigned char *)":Data:Models:Block1collide.solid"); + + blockwalls[0].Rotate(90,0,0); + + blockwalls[0].Scale(.8,.75,.8); + + blockwalls[0].CalculateNormals(); + + + + blockwalls[1].load((unsigned char *)":Data:Models:Block2collide.solid"); + + blockwalls[1].Rotate(90,0,0); + + blockwalls[1].Scale(.8,.75,.8); + + blockwalls[1].CalculateNormals(); + + + + blockwalls[2].load((unsigned char *)":Data:Models:Block3collide.solid"); + + blockwalls[2].Rotate(90,0,0); + + blockwalls[2].Scale(.8,.75,.8); + + blockwalls[2].CalculateNormals(); + + + + blockwalls[3].load((unsigned char *)":Data:Models:Block4collide.solid"); + + blockwalls[3].Rotate(90,0,0); + + blockwalls[3].Scale(.8,.75,.8); + + blockwalls[3].CalculateNormals(); + + + + loadingscreenamount+=5; + + if(!initialized)LoadingScreen(loadingscreenamount/loadingscreenamounttotal*100); + + + + blockroofs[0].load((unsigned char *)":Data:Models:Highblock1collide.solid"); + + blockroofs[0].Rotate(90,0,0); + + blockroofs[0].Scale(.8,.8,.8); + + blockroofs[0].CalculateNormals(); + + + + blockroofs[1].load((unsigned char *)":Data:Models:Highblock2collide.solid"); + + blockroofs[1].Rotate(90,0,0); + + blockroofs[1].Scale(.8,.8,.8); + + blockroofs[1].CalculateNormals(); + + + + blockroofs[2].load((unsigned char *)":Data:Models:Highblock3collide.solid"); + + blockroofs[2].Rotate(90,0,0); + + blockroofs[2].Scale(.8,.8,.8); + + blockroofs[2].CalculateNormals(); + + + + blockroofs[3].load((unsigned char *)":Data:Models:Highblock4collide.solid"); + + blockroofs[3].Rotate(90,0,0); + + blockroofs[3].Scale(.8,.8,.8); + + blockroofs[3].CalculateNormals(); + + + + blockcollide[0].load((unsigned char *)":Data:Models:block1complete.solid"); + + blockcollide[0].Rotate(90,0,0); + + blockcollide[0].Scale(.8,.8,.8); + + blockcollide[0].CalculateNormals(); + + + + blockcollide[1].load((unsigned char *)":Data:Models:block2complete.solid"); + + blockcollide[1].Rotate(90,0,0); + + blockcollide[1].Scale(.8,.8,.8); + + blockcollide[1].CalculateNormals(); + + + + blockcollide[2].load((unsigned char *)":Data:Models:block3complete.solid"); + + blockcollide[2].Rotate(90,0,0); + + blockcollide[2].Scale(.8,.8,.8); + + blockcollide[2].CalculateNormals(); + + + + blockcollide[3].load((unsigned char *)":Data:Models:block4complete.solid"); + + blockcollide[3].Rotate(90,0,0); + + blockcollide[3].Scale(.8,.8,.8); + + blockcollide[3].CalculateNormals(); + + + + loadingscreenamount+=5; + + if(!initialized)LoadingScreen(loadingscreenamount/loadingscreenamounttotal*100); + + + + + + blocksimplecollide[0].load((unsigned char *)":Data:Models:lowsimplecollide1.solid"); + + blocksimplecollide[0].Rotate(90,0,0); + + blocksimplecollide[0].Scale(.8,.8,.8); + + blocksimplecollide[0].CalculateNormals(); + + + + blocksimplecollide[1].load((unsigned char *)":Data:Models:lowsimplecollide2.solid"); + + blocksimplecollide[1].Rotate(90,0,0); + + blocksimplecollide[1].Scale(.8,.8,.8); + + blocksimplecollide[1].CalculateNormals(); + + + + blocksimplecollide[2].load((unsigned char *)":Data:Models:lowsimplecollide3.solid"); + + blocksimplecollide[2].Rotate(90,0,0); + + blocksimplecollide[2].Scale(.8,.8,.8); + + blocksimplecollide[2].CalculateNormals(); + + + + blocksimplecollide[3].load((unsigned char *)":Data:Models:lowsimplecollide4.solid"); + + blocksimplecollide[3].Rotate(90,0,0); + + blocksimplecollide[3].Scale(.8,.8,.8); + + blocksimplecollide[3].CalculateNormals(); + + + + loadingscreenamount+=5; + + if(!initialized)LoadingScreen(loadingscreenamount/loadingscreenamounttotal*100); + + + + blockocclude.load((unsigned char *)":Data:Models:blockocclude.solid"); + + blockocclude.Rotate(90,0,0); + + blockocclude.Scale(.8,.8,.8); + + blockocclude.CalculateNormals(); + + + + blocksimple.load((unsigned char *)":Data:Models:blocksimple.solid"); + + blocksimple.Rotate(90,0,0); + + blocksimple.Scale(.8,2,.8); + + blocksimple.CalculateNormals(); + + + + street.load((unsigned char *)":Data:Models:streetsubdivided2.solid"); + + street.Rotate(90,0,0); + + street.Scale(.01,.01,.01); + + street.CalculateNormals(); + + + + Bigstreet=street; + + Bigstreet.Scale(10000,10000,10000); + + + + loadingscreenamount+=5; + + if(!initialized)LoadingScreen(loadingscreenamount/loadingscreenamounttotal*100); + + + + path.load((unsigned char *)":Data:Models:path.solid"); + + path.Rotate(90,0,0); + + path.Scale(.8,.8,.8); + + path.CalculateNormals(); + + + + //Fix block radius + + for(int i=0;i<4;i++){ + + blocks[i].boundingspherecenter.x=0; + + blocks[i].boundingspherecenter.z=0; + + blocks[i].boundingsphereradius=0; + + for(int x=0;iblocks[i].boundingsphereradius)blocks[i].boundingsphereradius=findDistancefast(blocks[i].boundingspherecenter,blocks[i].vertex[x]); + + } + + blocks[i].boundingsphereradius=sqrt(blocks[i].boundingsphereradius); + + } + + } + + mousesensitivity=1; + + + + //init city block rotations + + for(i=0;i3)citytype[i][j]=3; + + } + + } + + + + if(!initialized){ + + //Load player model + + skeletonmodels[0].load((unsigned char *)":Data:Models:Head.solid"); + + skeletonmodels[0].Rotate(90,0,0); + + skeletonmodels[0].Scale(.02,.02,.02); + + skeletonmodels[0].CalculateNormals(); + + + + skeletonmodels[1].load((unsigned char *)":Data:Models:Chest.solid"); + + skeletonmodels[1].Rotate(90,0,0); + + skeletonmodels[1].Scale(.02,.02,.02); + + skeletonmodels[1].CalculateNormals(); + + + + skeletonmodels[2].load((unsigned char *)":Data:Models:Abdomen.solid"); + + skeletonmodels[2].Rotate(90,0,0); + + skeletonmodels[2].Scale(.02,.02,.02); + + skeletonmodels[2].CalculateNormals(); + + + + skeletonmodels[3].load((unsigned char *)":Data:Models:Upper arm.solid"); + + skeletonmodels[3].Rotate(90,0,0); + + skeletonmodels[3].Scale(.02,.02,.02); + + skeletonmodels[3].CalculateNormals(); + + + + skeletonmodels[4].load((unsigned char *)":Data:Models:Lower arm.solid"); + + skeletonmodels[4].Rotate(90,0,0); + + skeletonmodels[4].Scale(.02,.02,.02); + + skeletonmodels[4].CalculateNormals(); + + + + skeletonmodels[5].load((unsigned char *)":Data:Models:Hand.solid"); + + skeletonmodels[5].Rotate(90,0,0); + + skeletonmodels[5].Scale(.02,.02,.02); + + skeletonmodels[5].CalculateNormals(); + + + + skeletonmodels[6].load((unsigned char *)":Data:Models:Upper leg.solid"); + + skeletonmodels[6].Rotate(90,0,0); + + skeletonmodels[6].Scale(.02,.02,.02); + + skeletonmodels[6].CalculateNormals(); + + + + skeletonmodels[7].load((unsigned char *)":Data:Models:Lower leg.solid"); + + skeletonmodels[7].Rotate(90,0,0); + + skeletonmodels[7].Scale(.02,.02,.02); + + skeletonmodels[7].CalculateNormals(); + + + + skeletonmodels[8].load((unsigned char *)":Data:Models:Foot.solid"); + + skeletonmodels[8].Rotate(90,0,0); + + skeletonmodels[8].Scale(.02,.02,.02); + + skeletonmodels[8].CalculateNormals(); + + + + skeletonmodels[9].load((unsigned char *)":Data:Models:Shades.solid"); + + skeletonmodels[9].Rotate(90,0,0); + + skeletonmodels[9].Scale(.02,.02,.02); + + skeletonmodels[9].CalculateNormals(); + + + + //Load gun models + + loadingscreenamount+=5; + + if(!initialized)LoadingScreen(loadingscreenamount/loadingscreenamounttotal*100); + + + + gunmodels[sniperriflemodel].load((unsigned char *)":Data:Models:sniperrifle.solid"); + + gunmodels[sniperriflemodel].Rotate(0,0,90); + + gunmodels[sniperriflemodel].Scale(.001,.001,.001); + + gunmodels[sniperriflemodel].CalculateNormals(); + + + + gunmodels[assaultriflemodel].load((unsigned char *)":Data:Models:assaultrifle.solid"); + + gunmodels[assaultriflemodel].Rotate(0,0,90); + + gunmodels[assaultriflemodel].Scale(.01,.01,.01); + + gunmodels[assaultriflemodel].CalculateNormals(); + + + + gunmodels[handgunbasemodel].load((unsigned char *)":Data:Models:Handgunbase.solid"); + + gunmodels[handgunbasemodel].Rotate(0,0,90); + + gunmodels[handgunbasemodel].Rotate(180,0,0); + + gunmodels[handgunbasemodel].Scale(.014,.014,.014); + + gunmodels[handgunbasemodel].CalculateNormals(); + + gunmodels[handgunbasemodel].MultColor(.6); + + loadingscreenamount+=5; + + if(!initialized)LoadingScreen(loadingscreenamount/loadingscreenamounttotal*100); + + + + gunmodels[handgunslidemodel].load((unsigned char *)":Data:Models:Handgunslide.solid"); + + gunmodels[handgunslidemodel].Rotate(0,0,90); + + gunmodels[handgunslidemodel].Rotate(180,0,0); + + gunmodels[handgunslidemodel].Scale(.014,.014,.014); + + gunmodels[handgunslidemodel].CalculateNormals(); + + gunmodels[handgunslidemodel].MultColor(.6); + + + + gunmodels[handgun2basemodel].load((unsigned char *)":Data:Models:glockbase.solid"); + + gunmodels[handgun2basemodel].Rotate(0,0,90); + + gunmodels[handgun2basemodel].Rotate(180,0,0); + + gunmodels[handgun2basemodel].Scale(.014,.014,.014); + + gunmodels[handgun2basemodel].CalculateNormals(); + + gunmodels[handgun2basemodel].MultColor(.6); + + + + gunmodels[handgun2slidemodel].load((unsigned char *)":Data:Models:glockslide.solid"); + + gunmodels[handgun2slidemodel].Rotate(0,0,90); + + gunmodels[handgun2slidemodel].Rotate(180,0,0); + + gunmodels[handgun2slidemodel].Scale(.014,.014,.014); + + gunmodels[handgun2slidemodel].CalculateNormals(); + + gunmodels[handgun2slidemodel].MultColor(.6); + + loadingscreenamount+=5; + + if(!initialized)LoadingScreen(loadingscreenamount/loadingscreenamounttotal*100); + + + + gunmodels[grenadebasemodel].load((unsigned char *)":Data:Models:grenadebase.solid"); + + gunmodels[grenadebasemodel].Rotate(0,0,90); + + gunmodels[grenadebasemodel].Rotate(180,0,0); + + gunmodels[grenadebasemodel].Scale(.014,.014,.014); + + gunmodels[grenadebasemodel].CalculateNormals(); + + + + gunmodels[grenadepinmodel].load((unsigned char *)":Data:Models:grenadepin.solid"); + + gunmodels[grenadepinmodel].Rotate(0,0,90); + + gunmodels[grenadepinmodel].Rotate(180,0,0); + + gunmodels[grenadepinmodel].Scale(.014,.014,.014); + + gunmodels[grenadepinmodel].CalculateNormals(); + + + + gunmodels[grenadespoonmodel].load((unsigned char *)":Data:Models:grenadespoon.solid"); + + gunmodels[grenadespoonmodel].Rotate(0,0,90); + + gunmodels[grenadespoonmodel].Rotate(180,0,0); + + gunmodels[grenadespoonmodel].Scale(.014,.014,.014); + + gunmodels[grenadespoonmodel].CalculateNormals(); + + + + gunmodels[knifemodel].load((unsigned char *)":Data:Models:Knife.solid"); + + gunmodels[knifemodel].Rotate(0,0,90); + + gunmodels[knifemodel].Rotate(180,0,0); + + gunmodels[knifemodel].Scale(.014,.014,.014); + + gunmodels[knifemodel].CalculateNormals(); + + + + gunmodels[shotgunmodel].load((unsigned char *)":Data:Models:shotgun.solid"); + + gunmodels[shotgunmodel].Rotate(0,0,90); + + gunmodels[shotgunmodel].Scale(.001,.001,.001); + + gunmodels[shotgunmodel].CalculateNormals(); + + gunmodels[shotgunmodel].MultColor(.6); + + } + + + + loadingscreenamount+=5; + + if(!initialized)LoadingScreen(loadingscreenamount/loadingscreenamounttotal*100); + + + + //Setup costumes + + float headcolor[3]; + + float footcolor[3]; + + float handcolor[3]; + + float topcolor[3]; + + float bottomcolor[3]; + + //Police + + headcolor[0]=(float)240/255; + + headcolor[1]=(float)183/255; + + headcolor[2]=(float)132/255; + + + + footcolor[0]=(float)119/255; + + footcolor[1]=(float)68/255; + + footcolor[2]=(float)18/255; + + + + handcolor[0]=(float)240/255; + + handcolor[1]=(float)183/255; + + handcolor[2]=(float)132/255; + + + + topcolor[0]=(float)14/255; + + topcolor[1]=(float)18/255; + + topcolor[2]=(float)195/255; + + + + bottomcolor[0]=(float)14/255; + + bottomcolor[1]=(float)18/255; + + bottomcolor[2]=(float)195/255; + + + + //Greenish skin if zombies + + if(type==zombie_type){ + + headcolor[0]=(float)223/255; + + headcolor[1]=(float)243/255; + + headcolor[2]=(float)197/255; + + + + handcolor[0]=(float)223/255; + + handcolor[1]=(float)243/255; + + handcolor[2]=(float)197/255; + + } + + + + costume[policecostume].headcolor[0]=headcolor[0]; + + costume[policecostume].headcolor[1]=headcolor[1]; + + costume[policecostume].headcolor[2]=headcolor[2]; + + + + costume[policecostume].handcolor[0]=handcolor[0]; + + costume[policecostume].handcolor[1]=handcolor[1]; + + costume[policecostume].handcolor[2]=handcolor[2]; + + + + costume[policecostume].chestcolor[0]=topcolor[0]; + + costume[policecostume].chestcolor[1]=topcolor[1]; + + costume[policecostume].chestcolor[2]=topcolor[2]; + + + + costume[policecostume].abdomencolor[0]=topcolor[0]; + + costume[policecostume].abdomencolor[1]=topcolor[1]; + + costume[policecostume].abdomencolor[2]=topcolor[2]; + + + + costume[policecostume].upperarmcolor[0]=topcolor[0]; + + costume[policecostume].upperarmcolor[1]=topcolor[1]; + + costume[policecostume].upperarmcolor[2]=topcolor[2]; + + + + costume[policecostume].lowerarmcolor[0]=topcolor[0]; + + costume[policecostume].lowerarmcolor[1]=topcolor[1]; + + costume[policecostume].lowerarmcolor[2]=topcolor[2]; + + + + costume[policecostume].upperlegcolor[0]=bottomcolor[0]; + + costume[policecostume].upperlegcolor[1]=bottomcolor[1]; + + costume[policecostume].upperlegcolor[2]=bottomcolor[2]; + + + + costume[policecostume].lowerlegcolor[0]=bottomcolor[0]; + + costume[policecostume].lowerlegcolor[1]=bottomcolor[1]; + + costume[policecostume].lowerlegcolor[2]=bottomcolor[2]; + + + + costume[policecostume].footcolor[0]=footcolor[0]; + + costume[policecostume].footcolor[1]=footcolor[1]; + + costume[policecostume].footcolor[2]=footcolor[2]; + + + + //casual + + topcolor[0]=(float)14/255; + + topcolor[1]=(float)200/255; + + topcolor[2]=(float)30/255; + + + + bottomcolor[0]=(float)14/255; + + bottomcolor[1]=(float)18/255; + + bottomcolor[2]=(float)195/255; + + + + costume[casualcostumes].headcolor[0]=headcolor[0]; + + costume[casualcostumes].headcolor[1]=headcolor[1]; + + costume[casualcostumes].headcolor[2]=headcolor[2]; + + + + costume[casualcostumes].handcolor[0]=handcolor[0]; + + costume[casualcostumes].handcolor[1]=handcolor[1]; + + costume[casualcostumes].handcolor[2]=handcolor[2]; + + + + costume[casualcostumes].chestcolor[0]=topcolor[0]; + + costume[casualcostumes].chestcolor[1]=topcolor[1]; + + costume[casualcostumes].chestcolor[2]=topcolor[2]; + + + + costume[casualcostumes].abdomencolor[0]=topcolor[0]; + + costume[casualcostumes].abdomencolor[1]=topcolor[1]; + + costume[casualcostumes].abdomencolor[2]=topcolor[2]; + + + + costume[casualcostumes].upperarmcolor[0]=topcolor[0]; + + costume[casualcostumes].upperarmcolor[1]=topcolor[1]; + + costume[casualcostumes].upperarmcolor[2]=topcolor[2]; + + + + costume[casualcostumes].lowerarmcolor[0]=handcolor[0]; + + costume[casualcostumes].lowerarmcolor[1]=handcolor[1]; + + costume[casualcostumes].lowerarmcolor[2]=handcolor[2]; + + + + costume[casualcostumes].upperlegcolor[0]=bottomcolor[0]; + + costume[casualcostumes].upperlegcolor[1]=bottomcolor[1]; + + costume[casualcostumes].upperlegcolor[2]=bottomcolor[2]; + + + + costume[casualcostumes].lowerlegcolor[0]=bottomcolor[0]; + + costume[casualcostumes].lowerlegcolor[1]=bottomcolor[1]; + + costume[casualcostumes].lowerlegcolor[2]=bottomcolor[2]; + + + + costume[casualcostumes].footcolor[0]=footcolor[0]; + + costume[casualcostumes].footcolor[1]=footcolor[1]; + + costume[casualcostumes].footcolor[2]=footcolor[2]; + + + + //casual 2 + + topcolor[0]=(float)140/255; + + topcolor[1]=(float)55/255; + + topcolor[2]=(float)4/255; + + + + bottomcolor[0]=(float)14/255; + + bottomcolor[1]=(float)18/255; + + bottomcolor[2]=(float)135/255; + + + + costume[casualcostumes+1].headcolor[0]=headcolor[0]; + + costume[casualcostumes+1].headcolor[1]=headcolor[1]; + + costume[casualcostumes+1].headcolor[2]=headcolor[2]; + + + + costume[casualcostumes+1].handcolor[0]=handcolor[0]; + + costume[casualcostumes+1].handcolor[1]=handcolor[1]; + + costume[casualcostumes+1].handcolor[2]=handcolor[2]; + + + + costume[casualcostumes+1].chestcolor[0]=topcolor[0]; + + costume[casualcostumes+1].chestcolor[1]=topcolor[1]; + + costume[casualcostumes+1].chestcolor[2]=topcolor[2]; + + + + costume[casualcostumes+1].abdomencolor[0]=topcolor[0]; + + costume[casualcostumes+1].abdomencolor[1]=topcolor[1]; + + costume[casualcostumes+1].abdomencolor[2]=topcolor[2]; + + + + costume[casualcostumes+1].upperarmcolor[0]=topcolor[0]; + + costume[casualcostumes+1].upperarmcolor[1]=topcolor[1]; + + costume[casualcostumes+1].upperarmcolor[2]=topcolor[2]; + + + + costume[casualcostumes+1].lowerarmcolor[0]=topcolor[0]; + + costume[casualcostumes+1].lowerarmcolor[1]=topcolor[1]; + + costume[casualcostumes+1].lowerarmcolor[2]=topcolor[2]; + + + + costume[casualcostumes+1].upperlegcolor[0]=bottomcolor[0]; + + costume[casualcostumes+1].upperlegcolor[1]=bottomcolor[1]; + + costume[casualcostumes+1].upperlegcolor[2]=bottomcolor[2]; + + + + costume[casualcostumes+1].lowerlegcolor[0]=bottomcolor[0]; + + costume[casualcostumes+1].lowerlegcolor[1]=bottomcolor[1]; + + costume[casualcostumes+1].lowerlegcolor[2]=bottomcolor[2]; + + + + costume[casualcostumes+1].footcolor[0]=footcolor[0]; + + costume[casualcostumes+1].footcolor[1]=footcolor[1]; + + costume[casualcostumes+1].footcolor[2]=footcolor[2]; + + + + //casual 3 + + topcolor[0]=(float)134/255; + + topcolor[1]=(float)80/255; + + topcolor[2]=(float)3/255; + + + + bottomcolor[0]=(float)30/255; + + bottomcolor[1]=(float)30/255; + + bottomcolor[2]=(float)30/255; + + + + footcolor[0]=(float)20/255; + + footcolor[1]=(float)20/255; + + footcolor[2]=(float)20/255; + + + + + + costume[casualcostumes+2].headcolor[0]=headcolor[0]; + + costume[casualcostumes+2].headcolor[1]=headcolor[1]; + + costume[casualcostumes+2].headcolor[2]=headcolor[2]; + + + + costume[casualcostumes+2].handcolor[0]=handcolor[0]; + + costume[casualcostumes+2].handcolor[1]=handcolor[1]; + + costume[casualcostumes+2].handcolor[2]=handcolor[2]; + + + + costume[casualcostumes+2].chestcolor[0]=topcolor[0]; + + costume[casualcostumes+2].chestcolor[1]=topcolor[1]; + + costume[casualcostumes+2].chestcolor[2]=topcolor[2]; + + + + costume[casualcostumes+2].abdomencolor[0]=topcolor[0]; + + costume[casualcostumes+2].abdomencolor[1]=topcolor[1]; + + costume[casualcostumes+2].abdomencolor[2]=topcolor[2]; + + + + costume[casualcostumes+2].upperarmcolor[0]=topcolor[0]; + + costume[casualcostumes+2].upperarmcolor[1]=topcolor[1]; + + costume[casualcostumes+2].upperarmcolor[2]=topcolor[2]; + + + + costume[casualcostumes+2].lowerarmcolor[0]=topcolor[0]; + + costume[casualcostumes+2].lowerarmcolor[1]=topcolor[1]; + + costume[casualcostumes+2].lowerarmcolor[2]=topcolor[2]; + + + + costume[casualcostumes+2].upperlegcolor[0]=bottomcolor[0]; + + costume[casualcostumes+2].upperlegcolor[1]=bottomcolor[1]; + + costume[casualcostumes+2].upperlegcolor[2]=bottomcolor[2]; + + + + costume[casualcostumes+2].lowerlegcolor[0]=bottomcolor[0]; + + costume[casualcostumes+2].lowerlegcolor[1]=bottomcolor[1]; + + costume[casualcostumes+2].lowerlegcolor[2]=bottomcolor[2]; + + + + costume[casualcostumes+2].footcolor[0]=footcolor[0]; + + costume[casualcostumes+2].footcolor[1]=footcolor[1]; + + costume[casualcostumes+2].footcolor[2]=footcolor[2]; + + + + //casual 4 + + topcolor[0]=(float)228/255; + + topcolor[1]=(float)220/255; + + topcolor[2]=(float)0/255; + + + + bottomcolor[0]=(float)20/255; + + bottomcolor[1]=(float)20/255; + + bottomcolor[2]=(float)20/255; + + + + footcolor[0]=(float)119/255; + + footcolor[1]=(float)68/255; + + footcolor[2]=(float)18/255; + + + + costume[casualcostumes+3].headcolor[0]=headcolor[0]; + + costume[casualcostumes+3].headcolor[1]=headcolor[1]; + + costume[casualcostumes+3].headcolor[2]=headcolor[2]; + + + + costume[casualcostumes+3].handcolor[0]=handcolor[0]; + + costume[casualcostumes+3].handcolor[1]=handcolor[1]; + + costume[casualcostumes+3].handcolor[2]=handcolor[2]; + + + + costume[casualcostumes+3].chestcolor[0]=topcolor[0]; + + costume[casualcostumes+3].chestcolor[1]=topcolor[1]; + + costume[casualcostumes+3].chestcolor[2]=topcolor[2]; + + + + costume[casualcostumes+3].abdomencolor[0]=topcolor[0]; + + costume[casualcostumes+3].abdomencolor[1]=topcolor[1]; + + costume[casualcostumes+3].abdomencolor[2]=topcolor[2]; + + + + costume[casualcostumes+3].upperarmcolor[0]=topcolor[0]; + + costume[casualcostumes+3].upperarmcolor[1]=topcolor[1]; + + costume[casualcostumes+3].upperarmcolor[2]=topcolor[2]; + + + + costume[casualcostumes+3].lowerarmcolor[0]=handcolor[0]; + + costume[casualcostumes+3].lowerarmcolor[1]=handcolor[1]; + + costume[casualcostumes+3].lowerarmcolor[2]=handcolor[2]; + + + + costume[casualcostumes+3].upperlegcolor[0]=bottomcolor[0]; + + costume[casualcostumes+3].upperlegcolor[1]=bottomcolor[1]; + + costume[casualcostumes+3].upperlegcolor[2]=bottomcolor[2]; + + + + costume[casualcostumes+3].lowerlegcolor[0]=bottomcolor[0]; + + costume[casualcostumes+3].lowerlegcolor[1]=bottomcolor[1]; + + costume[casualcostumes+3].lowerlegcolor[2]=bottomcolor[2]; + + + + costume[casualcostumes+3].footcolor[0]=footcolor[0]; + + costume[casualcostumes+3].footcolor[1]=footcolor[1]; + + costume[casualcostumes+3].footcolor[2]=footcolor[2]; + + + + if(!initialized){ + + //vip + + topcolor[0]=(float)235/255; + + topcolor[1]=(float)235/255; + + topcolor[2]=(float)235/255; + + + + bottomcolor[0]=(float)200/255; + + bottomcolor[1]=(float)200/255; + + bottomcolor[2]=(float)200/255; + + + + footcolor[0]=(float)119/255; + + footcolor[1]=(float)68/255; + + footcolor[2]=(float)18/255; + + + + headcolor[0]=(float)240/255; + + headcolor[1]=(float)183/255; + + headcolor[2]=(float)132/255; + + + + footcolor[0]=(float)119/255; + + footcolor[1]=(float)68/255; + + footcolor[2]=(float)18/255; + + + + handcolor[0]=(float)240/255; + + handcolor[1]=(float)183/255; + + handcolor[2]=(float)132/255; + + + + costume[vipcostume].headcolor[0]=headcolor[0]; + + costume[vipcostume].headcolor[1]=headcolor[1]; + + costume[vipcostume].headcolor[2]=headcolor[2]; + + + + costume[vipcostume].handcolor[0]=handcolor[0]; + + costume[vipcostume].handcolor[1]=handcolor[1]; + + costume[vipcostume].handcolor[2]=handcolor[2]; + + + + costume[vipcostume].chestcolor[0]=topcolor[0]; + + costume[vipcostume].chestcolor[1]=topcolor[1]; + + costume[vipcostume].chestcolor[2]=topcolor[2]; + + + + costume[vipcostume].abdomencolor[0]=topcolor[0]; + + costume[vipcostume].abdomencolor[1]=topcolor[1]; + + costume[vipcostume].abdomencolor[2]=topcolor[2]; + + + + costume[vipcostume].upperarmcolor[0]=topcolor[0]; + + costume[vipcostume].upperarmcolor[1]=topcolor[1]; + + costume[vipcostume].upperarmcolor[2]=topcolor[2]; + + + + costume[vipcostume].lowerarmcolor[0]=topcolor[0]; + + costume[vipcostume].lowerarmcolor[1]=topcolor[1]; + + costume[vipcostume].lowerarmcolor[2]=topcolor[2]; + + + + costume[vipcostume].upperlegcolor[0]=bottomcolor[0]; + + costume[vipcostume].upperlegcolor[1]=bottomcolor[1]; + + costume[vipcostume].upperlegcolor[2]=bottomcolor[2]; + + + + costume[vipcostume].lowerlegcolor[0]=bottomcolor[0]; + + costume[vipcostume].lowerlegcolor[1]=bottomcolor[1]; + + costume[vipcostume].lowerlegcolor[2]=bottomcolor[2]; + + + + costume[vipcostume].footcolor[0]=footcolor[0]; + + costume[vipcostume].footcolor[1]=footcolor[1]; + + costume[vipcostume].footcolor[2]=footcolor[2]; + + + + //Bodyguard + + topcolor[0]=(float)50/255; + + topcolor[1]=(float)50/255; + + topcolor[2]=(float)50/255; + + + + bottomcolor[0]=(float)30/255; + + bottomcolor[1]=(float)30/255; + + bottomcolor[2]=(float)30/255; + + + + footcolor[0]=(float)20/255; + + footcolor[1]=(float)20/255; + + footcolor[2]=(float)20/255; + + + + costume[bodyguardcostume].headcolor[0]=headcolor[0]; + + costume[bodyguardcostume].headcolor[1]=headcolor[1]; + + costume[bodyguardcostume].headcolor[2]=headcolor[2]; + + + + costume[bodyguardcostume].handcolor[0]=handcolor[0]; + + costume[bodyguardcostume].handcolor[1]=handcolor[1]; + + costume[bodyguardcostume].handcolor[2]=handcolor[2]; + + + + costume[bodyguardcostume].chestcolor[0]=topcolor[0]; + + costume[bodyguardcostume].chestcolor[1]=topcolor[1]; + + costume[bodyguardcostume].chestcolor[2]=topcolor[2]; + + + + costume[bodyguardcostume].abdomencolor[0]=topcolor[0]; + + costume[bodyguardcostume].abdomencolor[1]=topcolor[1]; + + costume[bodyguardcostume].abdomencolor[2]=topcolor[2]; + + + + costume[bodyguardcostume].upperarmcolor[0]=topcolor[0]; + + costume[bodyguardcostume].upperarmcolor[1]=topcolor[1]; + + costume[bodyguardcostume].upperarmcolor[2]=topcolor[2]; + + + + costume[bodyguardcostume].lowerarmcolor[0]=topcolor[0]; + + costume[bodyguardcostume].lowerarmcolor[1]=topcolor[1]; + + costume[bodyguardcostume].lowerarmcolor[2]=topcolor[2]; + + + + costume[bodyguardcostume].upperlegcolor[0]=bottomcolor[0]; + + costume[bodyguardcostume].upperlegcolor[1]=bottomcolor[1]; + + costume[bodyguardcostume].upperlegcolor[2]=bottomcolor[2]; + + + + costume[bodyguardcostume].lowerlegcolor[0]=bottomcolor[0]; + + costume[bodyguardcostume].lowerlegcolor[1]=bottomcolor[1]; + + costume[bodyguardcostume].lowerlegcolor[2]=bottomcolor[2]; + + + + costume[bodyguardcostume].footcolor[0]=footcolor[0]; + + costume[bodyguardcostume].footcolor[1]=footcolor[1]; + + costume[bodyguardcostume].footcolor[2]=footcolor[2]; + + + + //Load animations + + loadingscreenamount+=5; + + if(!initialized)LoadingScreen(loadingscreenamount/loadingscreenamounttotal*100); + + + + testskeleton.Load((char *)":Data:Skeleton:Basic Figure"); + + animation[idleanim].Load((char *)":Data:Animations:Breathe"); + + animation[joganim].Load((char *)":Data:Animations:Run"); + + animation[pistolaimanim].Load((char *)":Data:Animations:PistolAim"); + + loadingscreenamount+=5; + + if(!initialized)LoadingScreen(loadingscreenamount/loadingscreenamounttotal*100); + + animation[walkanim].Load((char *)":Data:Animations:Walk"); + + animation[rifleholdanim].Load((char *)":Data:Animations:Riflehold"); + + animation[rifleaimanim].Load((char *)":Data:Animations:Rifleaim"); + + animation[assaultrifleaimanim].Load((char *)":Data:Animations:AssaultRifleaim"); + + animation[crouchanim].Load((char *)":Data:Animations:Crouch"); + + loadingscreenamount+=5; + + if(!initialized)LoadingScreen(loadingscreenamount/loadingscreenamounttotal*100); + + animation[headpainanim].Load((char *)":Data:Animations:Headshot"); + + animation[chestpainanim].Load((char *)":Data:Animations:Chestshot"); + + animation[stomachpainanim].Load((char *)":Data:Animations:Stomachshot"); + + animation[rightarmpainanim].Load((char *)":Data:Animations:Rightarmshot"); + + animation[leftarmpainanim].Load((char *)":Data:Animations:Leftarmshot"); + + loadingscreenamount+=5; + + if(!initialized)LoadingScreen(loadingscreenamount/loadingscreenamounttotal*100); + + animation[rightlegpainanim].Load((char *)":Data:Animations:Rightlegshot"); + + animation[leftlegpainanim].Load((char *)":Data:Animations:Leftlegshot"); + + animation[riflehitanim].Load((char *)":Data:Animations:Riflehit"); + + animation[grenadeaimanim].Load((char *)":Data:Animations:grenadeaim"); + + animation[grenadechargeanim].Load((char *)":Data:Animations:grenadecharge"); + + loadingscreenamount+=5; + + if(!initialized)LoadingScreen(loadingscreenamount/loadingscreenamounttotal*100); + + animation[grenadethrowanim].Load((char *)":Data:Animations:grenadethrow"); + + animation[zombieeatanim].Load((char *)":Data:Animations:Zombiemunch"); + + animation[zombiejoganim].Load((char *)":Data:Animations:ZombieRun"); + + animation[zombiewalkanim].Load((char *)":Data:Animations:Zombiewalk"); + + loadingscreenamount+=5; + + if(!initialized)LoadingScreen(loadingscreenamount/loadingscreenamounttotal*100); + + animation[getupfrontanim].Load((char *)":Data:Animations:Getupfromfront"); + + animation[getupbackanim].Load((char *)":Data:Animations:Getupfromback",180); + + animation[diveanim].Load((char *)":Data:Animations:Dive"); + + animation[throwanim].Load((char *)":Data:Animations:Aikidothrow"); + + animation[thrownanim].Load((char *)":Data:Animations:Aikidothrown"); + + } + + + + //Setup people + + for(i=0;i1){ + + person[i].whichcostume=casualcostumes+abs(Random())%numcasual; + + } + + //person[i].firstlongdead=0; + + person[i].dead=0; + + person[i].health=100; + + person[i].skeleton.free=0; + + person[i].ammo=0; + + person[i].velocity=0; + + //Load skeleton structure + + if(!initialized)person[i].skeleton.Load((char *)":Data:Skeleton:Basic Figure"); + + + + if(i%5==0){ + + loadingscreenamount+=5; + + if(!initialized)LoadingScreen(loadingscreenamount/loadingscreenamounttotal*100); + + } + + } + + + + loadingscreenamount+=5; + + if(!initialized)LoadingScreen(loadingscreenamount/loadingscreenamounttotal*100); + + + + if(initialized)person[0].skeleton.Load((char *)":Data:Skeleton:Basic Figure"); + + + + person[0].attackframe=-1; + + + + spawndelay=0; + + + + fog.SetFog(fogcolorr,fogcolorg,fogcolorb,0,viewdistance*.8,.1); + + + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + + + + + //light + + GLfloat LightAmbient[]= { .3, .3, .3, 1.0f}; + + GLfloat LightDiffuse[]= { 1, 1, 1, 1.0f }; + + + + glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmbient); + + glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDiffuse); + + glEnable(GL_LIGHT0); + + + + loadingscreenamount+=5; + + + + //Load some textures + + if(!initialized){ + + LoadingScreen(loadingscreenamount/loadingscreenamounttotal*100); + + + + + + LoadPersonSpriteTexture(":Data:Textures:Personsprite.tga",&personspritetextureptr); + + LoadPersonSpriteTexture(":Data:Textures:DeadPersonsprite.tga",&deadpersonspritetextureptr); + + LoadPersonSpriteTexture(":Data:Textures:Scope.tga",&scopetextureptr); + + LoadPersonSpriteTexture(":Data:Textures:Flare.tga",&flaretextureptr); + + + + sprites.LoadFlareTexture(":Data:Textures:HitFlash.tga"); + + sprites.LoadMuzzleFlareTexture(":Data:Textures:MuzzleFlash.tga"); + + sprites.LoadSmokeTexture(":Data:Textures:Smoke.tga"); + + sprites.LoadBloodTexture(":Data:Textures:Blood.tga"); + + sprites.LoadRainTexture(":Data:Textures:rain.tga"); + + sprites.LoadSnowTexture(":Data:Textures:snow.tga"); + + decals.LoadBulletHoleTexture(":Data:Textures:BulletHole.tga"); + + decals.LoadCraterTexture(":Data:Textures:Crater.tga"); + + decals.LoadBloodTexture(":Data:Textures:Blood:Blood1.tga",0); + + decals.LoadBloodTexture(":Data:Textures:Blood:Blood2.tga",1); + + decals.LoadBloodTexture(":Data:Textures:Blood:Blood3.tga",2); + + decals.LoadBloodTexture(":Data:Textures:Blood:Blood4.tga",3); + + decals.LoadBloodTexture(":Data:Textures:Blood:Blood5.tga",4); + + decals.LoadBloodTexture(":Data:Textures:Blood:Blood6.tga",5); + + decals.LoadBloodTexture(":Data:Textures:Blood:Blood7.tga",6); + + decals.LoadBloodTexture(":Data:Textures:Blood:Blood8.tga",7); + + decals.LoadBloodTexture(":Data:Textures:Blood:Blood9.tga",8); + + decals.LoadBloodTexture(":Data:Textures:Blood:Blood10.tga",9); + + decals.LoadBloodTexture(":Data:Textures:Blood:Blood11.tga",10); + + } + + + + //Setup clip plane equation + + eqn[0]=0; + + eqn[1]=1; + + eqn[2]=0; + + eqn[3]=0; + + + + glClearColor(fogcolorr,fogcolorg,fogcolorb,1); + + + + if(!initialized)InitMouse(); + + + + //Draw city one frame to fix evil menu bug + + if(!initialized)mainmenu=2; + + + + if(!initialized){ + + LoadingScreen(loadingscreenamount/loadingscreenamounttotal*100); + + flashamount=1; + + flashr=1;flashg=1;flashb=1; + + //alSourcePlay(gSourceID[src_soulinsound]); + alSourcePlay(SoundFX::inst()->getFreeSource(gSampleSet[soulinsound], 1.0)); + + } + + + + initialized=1; + + + + loadingscreenamount+=5; + + + + //Sync to refresh rate + + if(vblsync){ + + GLint swapInt = 1; + +#ifdef OS9 + aglSetInteger(gOpenGLContext, AGL_SWAP_INTERVAL, &swapInt); +#else + +#endif + + + + + } + + /* + + for(int i=0;i InitGL() <*****/ + + + + + +int Game::InitGL(GLvoid) + +{ + + //Config + + if(!initialized){ + + //Default config in case config is not found +#ifdef OS9 + HideCursor(); +#else + STUB_FUNCTION; +#endif + + screenwidth = 640; + + screenheight = 480; + + usermousesensitivity=.7; + + debug=0; + + vblsync=1; + + blood = 1; + + blurness = 0; + + mainmenuness=1; + + customlevels=0; + + musictoggle=1; + + invertmouse=0; + + fpslimit=300; + + fullscreen=1; + + fov=90; + + + //If no config, write one + + std::ifstream ipstream("config.txt"); + + if(!ipstream) { + + std::ofstream opstream("config.txt"); + + opstream << "Screenwidth:\n"; + + opstream << screenwidth; + + opstream << "\nScreenheight:\n"; + + opstream << screenheight; + + opstream << "\nMouse sensitivity:\n"; + + opstream << usermousesensitivity; + + opstream << "\nShow fps and other info:\n"; + + opstream << debug; + + opstream << "\nVBL sync:\n"; + + opstream << vblsync; + + opstream << "\nBlood:\n"; + + opstream << blood; + + opstream << "\nBlur:\n"; + + opstream << blurness; + + opstream << "\nMain Menu:\n"; + + opstream << mainmenuness; + + opstream << "\nCustom levels:\n"; + + opstream << customlevels; + + opstream << "\nMusic:\n"; + + opstream << musictoggle; + + opstream << "\nazerty keyboard:\n"; + + opstream << azertykeyboard; + + opstream << "\ninvert mouse:\n"; + + opstream << invertmouse; + + opstream << "\nFps (frames per second) limit:\n"; + + opstream << fpslimit; + + opstream << "\nFull Screen:\n"; + + opstream << fullscreen; + + opstream << "\nFOV (Field of View):\n"; + + opstream << fov; + + opstream.close(); + + } + + //Read config + + if(ipstream){ + + ipstream.ignore(256,'\n'); + + ipstream >> screenwidth; + + ipstream.ignore(256,'\n'); + + ipstream.ignore(256,'\n'); + + ipstream >> screenheight; + + ipstream.ignore(256,'\n'); + + ipstream.ignore(256,'\n'); + + ipstream >> usermousesensitivity; + + ipstream.ignore(256,'\n'); + + ipstream.ignore(256,'\n'); + + ipstream >> debug; + + ipstream.ignore(256,'\n'); + + ipstream.ignore(256,'\n'); + + ipstream >> vblsync; + + ipstream.ignore(256,'\n'); + + ipstream.ignore(256,'\n'); + + ipstream >> blood; + + ipstream.ignore(256,'\n'); + + ipstream.ignore(256,'\n'); + + ipstream >> blurness; + + ipstream.ignore(256,'\n'); + + ipstream.ignore(256,'\n'); + + ipstream >> mainmenuness; + + ipstream.ignore(256,'\n'); + + ipstream.ignore(256,'\n'); + + ipstream >> customlevels; + + ipstream.ignore(256,'\n'); + + ipstream.ignore(256,'\n'); + + ipstream >> musictoggle; + + ipstream.ignore(256,'\n'); + + ipstream.ignore(256,'\n'); + + ipstream >> azertykeyboard; + + ipstream.ignore(256,'\n'); + + ipstream.ignore(256,'\n'); + + ipstream >> invertmouse; + + ipstream.ignore(256,'\n'); + + ipstream.ignore(256,'\n'); + + ipstream >> fpslimit; + + ipstream.ignore(256,'\n'); + + ipstream.ignore(256,'\n'); + + ipstream >> fullscreen; + + ipstream.ignore(256,'\n'); + + ipstream.ignore(256,'\n'); + + ipstream >> fov; + + ipstream.close(); + + } + + + + //Read high score +#ifdef OS9 + std::ifstream ipstream2(":Data:HighscoreRevenge"); +#else + /* TODO */ + std::ifstream ipstream2("Data/HighscoreRevenge"); +#endif + if(!ipstream2) { + + highscore=0; + + beatgame=0; + +#ifdef OS9 + std::ofstream opstream(":Data:HighscoreRevenge"); +#else + /* TODO */ + std::ofstream opstream("Data/HighscoreRevenge"); +#endif + opstream << highscore; + + opstream << "\n"; + + opstream << beatgame; + + opstream.close(); + + } + + if(ipstream2){ + + ipstream2 >> highscore; + + ipstream.ignore(256,'\n'); + + ipstream2 >> beatgame; + + ipstream2.close(); + + } + + + + sps=40; + + maxfps=fpslimit; + + + + disttest=1; + + cubetest=1; + + } + + + + //Setup screen +#ifdef OS9 + if(screenwidth<640||screenheight<480) + + theScreen = SetupScreen( 640, 480 ); + + else + + theScreen = SetupScreen( screenwidth, screenheight ); + + + + gOpenGLContext = SetupAGL( ( AGLDrawable )theScreen ); + + if ( !gOpenGLContext ) + + return; +#else + if (SDL_Init(SDL_INIT_VIDEO) == -1) { + fprintf(stderr, "SDL Init Video failed: %s\n", SDL_GetError()); + exit(EXIT_FAILURE); + } + + atexit(SDL_Quit); + + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + + if(screenwidth<640||screenheight<480) { + if (SDL_SetVideoMode(640, 480, 0, (fullscreen == 1 ? (SDL_OPENGL | SDL_FULLSCREEN) : SDL_OPENGL)) == NULL) { + fprintf(stderr, "(OpenGL) SDL SetVideoMode failed: %s\n", SDL_GetError()); + exit(EXIT_FAILURE); + } + } else { + if (SDL_SetVideoMode(screenwidth, screenheight, 0, (fullscreen == 1 ? (SDL_OPENGL | SDL_FULLSCREEN) : SDL_OPENGL)) == NULL) { + fprintf(stderr, "(OpenGL) SDL SetVideoMode failed: %s\n", SDL_GetError()); + exit(EXIT_FAILURE); + } + } + + SDL_WM_SetCaption("Black Shades Revenge Mod", "Black Shades Revenge Mod"); + SDL_Surface* icon = IMG_Load("Data/Icon.tga"); + SDL_SetColorKey(icon, SDL_SRCCOLORKEY, SDL_MapRGB(icon->format, 255, 0, 255)); + SDL_WM_SetIcon(icon, 0); + + SDL_EnableUNICODE(1); /* toggle it to ON */ + + SDL_ShowCursor(0); + SDL_WM_GrabInput(SDL_GRAB_ON); + +#endif + + + text.LoadFontTexture(":Data:Textures:Font.tga"); + + text.BuildFont(); + + glAlphaFunc(GL_GREATER, 0.01); + + glDepthFunc(GL_LESS); + + + + glPolygonOffset(-8,0); + + glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); + + + + return TRUE; + +} + + + +//***************> Dispose() <******/ + +void Game::Dispose() + +{ +#ifdef OS9 + CleanupAGL( gOpenGLContext ); + + ShutdownScreen( theScreen ); + + ShowCursor(); +#endif + + + //Delete sound sources + +// alDeleteSources(100, gSourceID); + + SoundFX::clean(); + + +} + + + +//***************> ResizeGLScene() <******/ + +GLvoid Game::ReSizeGLScene(float fov, float nearplane) +{ + if (screenheight==0) + { + screenheight=1; + } + + glViewport(0,0,screenwidth,screenheight); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(fov, + screenwidth/screenheight, + nearplane, + viewdistance); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} diff --git a/blackshades_revenge/Source/GameLoop.cpp b/blackshades_revenge/Source/GameLoop.cpp new file mode 100644 index 0000000..e94d63a --- /dev/null +++ b/blackshades_revenge/Source/GameLoop.cpp @@ -0,0 +1,558 @@ +#include "Game.h" +#include "SoundFX.h" + +extern double multiplier; + +extern int visions; + +extern unsigned int gSourceID[100]; + +extern unsigned int gSampleSet[100]; + +extern Camera camera; + +extern float rad2deg; + +extern Fog fog; + +extern int environment; + +extern int slomo; + +/********************> HandleKeyDown() <*****/ + +void Game::HandleKeyDown( char theChar ) + +{ + + XYZ facing; + + + + if(!mainmenu){ + + switch( theChar ) + + { + + case 'l': + if(!lasersight==1){lasersight=1;}else{lasersight=0;} + + break; + + case 'k': + + if(debug)timeremaining=0; + + break; + + + + case 'b': + + if(debug) + { + //alSourcePlay(gSourceID[src_soulinsound]); + SoundFX::inst()->playFX(gSampleSet[soulinsound], NULL, 1.0); + + if(!slomo)slomo=1; + else slomo=0; + } + + + + // Slow motion sound + alSourcef(SoundFX::inst()->getMusicSource(), AL_PITCH, slomo?((ALfloat)(.5)):((ALfloat)(1.0))); + + + break; + + case 'B': + + if(debug) + { + + SoundFX::inst()->playFX(gSampleSet[soulinsound], NULL, 1.0); + + paused=1-paused; + } + + break; + + case 'f': + + if(debug){ + + //alSourcePlay(SoundFX::inst()->getFreeSource(gSampleSet[souloutsound], 1.0)); + SoundFX::inst()->playFX(gSampleSet[souloutsound], NULL, 1.0f); + + //Facing + + facing=0; + + facing.z=-1; + + + + facing=DoRotation(facing,-camera.rotation2,0,0); + + facing=DoRotation(facing,0,0-camera.rotation,0); + + for(int i=1;i7)person[0].whichgun=0; + + }} + + break; + + } + + } + +} + + + +/********************> DoEvent() <*****/ + +#ifdef OS9 +void Game::DoEvent( EventRecord *event ) + +{ + + + + char theChar; + + + + switch ( event->what ) + + { + + case keyDown: + + case autoKey: + + theChar = event->message & charCodeMask; // Get the letter of the key pressed from the event message + + HandleKeyDown( theChar ); // Only some key presses are handled here because it is slower and less responsive + + break; + + } + + + + + +} +#endif + +#ifndef OS9 +static int mapinit = 0; +static int sdlkeymap[SDLK_LAST]; + +static unsigned char ourkeys[16]; + +static void init_sdlkeymap() +{ + int i; + + for (i = 0; i < SDLK_LAST; i++) { + sdlkeymap[i] = -1; + } + + sdlkeymap[SDLK_1] = MAC_1_KEY; + sdlkeymap[SDLK_2] = MAC_2_KEY; + sdlkeymap[SDLK_3] = MAC_3_KEY; + sdlkeymap[SDLK_4] = MAC_4_KEY; + sdlkeymap[SDLK_5] = MAC_5_KEY; + sdlkeymap[SDLK_6] = MAC_6_KEY; + sdlkeymap[SDLK_7] = MAC_7_KEY; + sdlkeymap[SDLK_8] = MAC_8_KEY; + sdlkeymap[SDLK_9] = MAC_9_KEY; + sdlkeymap[SDLK_0] = MAC_0_KEY; + sdlkeymap[SDLK_KP1] = MAC_NUMPAD_1_KEY; + sdlkeymap[SDLK_KP2] = MAC_NUMPAD_2_KEY; + sdlkeymap[SDLK_KP3] = MAC_NUMPAD_3_KEY; + sdlkeymap[SDLK_KP4] = MAC_NUMPAD_4_KEY; + sdlkeymap[SDLK_KP5] = MAC_NUMPAD_5_KEY; + sdlkeymap[SDLK_KP6] = MAC_NUMPAD_6_KEY; + sdlkeymap[SDLK_KP7] = MAC_NUMPAD_7_KEY; + sdlkeymap[SDLK_KP8] = MAC_NUMPAD_8_KEY; + sdlkeymap[SDLK_KP9] = MAC_NUMPAD_9_KEY; + sdlkeymap[SDLK_KP0] = MAC_NUMPAD_0_KEY; + sdlkeymap[SDLK_a] = MAC_A_KEY; + sdlkeymap[SDLK_b] = MAC_B_KEY; + sdlkeymap[SDLK_c] = MAC_C_KEY; + sdlkeymap[SDLK_d] = MAC_D_KEY; + sdlkeymap[SDLK_e] = MAC_E_KEY; + sdlkeymap[SDLK_f] = MAC_F_KEY; + sdlkeymap[SDLK_g] = MAC_G_KEY; + sdlkeymap[SDLK_h] = MAC_H_KEY; + sdlkeymap[SDLK_i] = MAC_I_KEY; + sdlkeymap[SDLK_j] = MAC_J_KEY; + sdlkeymap[SDLK_k] = MAC_K_KEY; + sdlkeymap[SDLK_l] = MAC_L_KEY; + sdlkeymap[SDLK_m] = MAC_M_KEY; + sdlkeymap[SDLK_n] = MAC_N_KEY; + sdlkeymap[SDLK_o] = MAC_O_KEY; + sdlkeymap[SDLK_p] = MAC_P_KEY; + sdlkeymap[SDLK_q] = MAC_Q_KEY; + sdlkeymap[SDLK_r] = MAC_R_KEY; + sdlkeymap[SDLK_s] = MAC_S_KEY; + sdlkeymap[SDLK_t] = MAC_T_KEY; + sdlkeymap[SDLK_u] = MAC_U_KEY; + sdlkeymap[SDLK_v] = MAC_V_KEY; + sdlkeymap[SDLK_w] = MAC_W_KEY; + sdlkeymap[SDLK_x] = MAC_X_KEY; + sdlkeymap[SDLK_y] = MAC_Y_KEY; + sdlkeymap[SDLK_z] = MAC_Z_KEY; + sdlkeymap[SDLK_F1] = MAC_F1_KEY; + sdlkeymap[SDLK_F2] = MAC_F2_KEY; + sdlkeymap[SDLK_F3] = MAC_F3_KEY; + sdlkeymap[SDLK_F4] = MAC_F4_KEY; + sdlkeymap[SDLK_F5] = MAC_F5_KEY; + sdlkeymap[SDLK_F6] = MAC_F6_KEY; + sdlkeymap[SDLK_F7] = MAC_F7_KEY; + sdlkeymap[SDLK_F8] = MAC_F8_KEY; + sdlkeymap[SDLK_F9] = MAC_F9_KEY; + sdlkeymap[SDLK_F10] = MAC_F10_KEY; + sdlkeymap[SDLK_F11] = MAC_F11_KEY; + sdlkeymap[SDLK_F12] = MAC_F12_KEY; + sdlkeymap[SDLK_RETURN] = MAC_RETURN_KEY; + sdlkeymap[SDLK_KP_ENTER] = MAC_ENTER_KEY; + sdlkeymap[SDLK_TAB] = MAC_TAB_KEY; + sdlkeymap[SDLK_SPACE] = MAC_SPACE_KEY; + sdlkeymap[SDLK_BACKSPACE] = MAC_DELETE_KEY; + sdlkeymap[SDLK_ESCAPE] = MAC_ESCAPE_KEY; + sdlkeymap[SDLK_LCTRL] = MAC_CONTROL_KEY; + sdlkeymap[SDLK_RCTRL] = MAC_CONTROL_KEY; + sdlkeymap[SDLK_LSHIFT] = MAC_SHIFT_KEY; + sdlkeymap[SDLK_RSHIFT] = MAC_SHIFT_KEY; + sdlkeymap[SDLK_CAPSLOCK] = MAC_CAPS_LOCK_KEY; + sdlkeymap[SDLK_LALT] = MAC_OPTION_KEY; + sdlkeymap[SDLK_RALT] = MAC_OPTION_KEY; + sdlkeymap[SDLK_PAGEUP] = MAC_PAGE_UP_KEY; + sdlkeymap[SDLK_PAGEDOWN] = MAC_PAGE_DOWN_KEY; + sdlkeymap[SDLK_INSERT] = MAC_INSERT_KEY; + sdlkeymap[SDLK_DELETE] = MAC_DEL_KEY; + sdlkeymap[SDLK_HOME] = MAC_HOME_KEY; + sdlkeymap[SDLK_END] = MAC_END_KEY; + sdlkeymap[SDLK_LEFTBRACKET] = MAC_LEFT_BRACKET_KEY; + sdlkeymap[SDLK_RIGHTBRACKET] = MAC_RIGHT_BRACKET_KEY; + sdlkeymap[SDLK_UP] = MAC_ARROW_UP_KEY; + sdlkeymap[SDLK_DOWN] = MAC_ARROW_DOWN_KEY; + sdlkeymap[SDLK_LEFT] = MAC_ARROW_LEFT_KEY; + sdlkeymap[SDLK_RIGHT] = MAC_ARROW_RIGHT_KEY; + + mapinit = 1; +} + +void GetKeys(unsigned long *keys) +{ + /* this is just weird */ + memcpy(keys, ourkeys, sizeof(ourkeys)); +} + +static void DoSDLKey(Game *g, SDL_Event *event) +{ + int press = (event->type == SDL_KEYDOWN) ? 1 : 0; + int mackey; + int index; + int mask; + + + if (mapinit == 0) { + init_sdlkeymap(); + } + + mackey = sdlkeymap[event->key.keysym.sym]; + + if (mackey != -1) { + index = mackey / 8; + mask = 1 << (mackey % 8); + + if (press) { + ourkeys[index] |= mask; + } else { + ourkeys[index] &= ~mask; + } + } + + if (event->key.keysym.unicode && + !(event->key.keysym.unicode & 0xFF80)) { + + /* hey, at least it was aleady public */ + g->HandleKeyDown(event->key.keysym.unicode); + } + + +} + +void Game::ProcessSDLEvents(void) +{ + SDL_Event event; + + if (SDL_PollEvent(&event)) { + do { + switch(event.type) { + case SDL_KEYDOWN: + if (event.key.keysym.sym == SDLK_RETURN && + event.key.keysym.mod & KMOD_ALT) + { + SDL_WM_ToggleFullScreen (SDL_GetVideoSurface ()); + break; + } + if (event.key.keysym.sym == SDLK_g && + event.key.keysym.mod & KMOD_CTRL) + { + if (SDL_WM_GrabInput (SDL_GRAB_QUERY) == SDL_GRAB_OFF) + { + SDL_WM_GrabInput (SDL_GRAB_ON); + SDL_ShowCursor (SDL_DISABLE); + } + else + { + SDL_WM_GrabInput (SDL_GRAB_OFF); + SDL_ShowCursor (SDL_ENABLE); + } + break; + } + case SDL_KEYUP: + DoSDLKey(this, &event); + break; + case SDL_QUIT: + exit(0); + } + } while (SDL_PollEvent(&event)); + } +} + +#endif + +/********************> EventLoop() <*****/ + +void Game::EventLoop( void ) + +{ + +#ifdef OS9 + EventRecord event; +#endif + + unsigned char theKeyMap[16]; + + int colaccuracy,i; + + GLfloat oldmult; + + gQuit = false; + + while ( gQuit == false ) + + { + +#ifdef OS9 + if ( GetNextEvent( everyEvent, &event ) ) + + DoEvent( &event ); +#else + ProcessSDLEvents(); +#endif + + + start=TimerGetTime(&theTimer); + + + + colaccuracy=sps/framespersecond+1; + + if(colaccuracy>sps){colaccuracy=sps;} + + + + oldmult=multiplier; + + multiplier/=colaccuracy; + + for(i=0;i<(int)(colaccuracy+.5);i++){ + + Tick(); + + } + + multiplier=oldmult; + + + + if ( DrawGLScene()) + +#ifdef OS9 + aglSwapBuffers( gOpenGLContext ); +#else + SDL_GL_SwapBuffers(); +#endif + + else + + gQuit = true; + + oldmult=multiplier; + + + + end=TimerGetTime(&theTimer); + + timetaken=end-start; + + framespersecond=600000000/timetaken; + + while(framespersecond>maxfps){ + + end=TimerGetTime(&theTimer); + + timetaken=end-start; + + framespersecond=600000000/timetaken; + + } + + multiplier5=multiplier4; + + multiplier4=multiplier3; + + multiplier3=multiplier2; + + multiplier2=1/framespersecond; + + multiplier=(multiplier2+multiplier3+multiplier4+multiplier5)/4; + + if(multiplier>1)multiplier=1; + + if(multiplier<.00001)multiplier=.00001; + + if(visions==1&&mainmenu==0)multiplier/=3; + + if(slomo)multiplier*=.2; + + if(paused)multiplier=0; + + GetKeys( ( unsigned long * )theKeyMap ); + + if ( IsKeyDown( theKeyMap, MAC_COMMAND_KEY )&&IsKeyDown( theKeyMap, MAC_Q_KEY )){ + + gQuit = true; + + if(score>highscore){ + + highscore=score; + +#ifdef OS9 + std::ofstream opstream(":Data:HighscoreRevenge"); +#else + /* TODO */ + std::ofstream opstream("Data/HighscoreRevenge"); +#endif + + opstream << highscore; + + opstream << "\n"; + + opstream << beatgame; + + opstream.close(); + + } + + } + + if ( IsKeyDown( theKeyMap, MAC_ESCAPE_KEY )){ + + float gLoc[3] = {0.0f, 0.0f, 0.0f}; + alListenerfv(AL_POSITION, gLoc); + + alSourcePause(SoundFX::inst()->getEnviroSource()); + + + + mainmenu=1; + + // hjk - Added because the soulout was blowing out my speaker cones. + gLoc[2] = 3.0; + SoundFX::inst()->playFX(gSampleSet[souloutsound],gLoc, 0.1, 0.1); + + flashamount=1; + + flashr=1;flashg=1;flashb=1; + + alSourceStop(SoundFX::inst()->getVisionSource()); + + if(musictoggle) + { + whichsong = mainmenusong; + + + ALuint music = SoundFX::inst()->getMusicSource(gSampleSet[whichsong]); + alSourcef(music, AL_PITCH, 1.0); + alSourcef(music, AL_MIN_GAIN, 1); + alSourcef(music, AL_MAX_GAIN, 1); + + alSourcePlay(music); + } + + } + + } + +} diff --git a/blackshades_revenge/Source/GameTick.cpp b/blackshades_revenge/Source/GameTick.cpp new file mode 100644 index 0000000..533b083 --- /dev/null +++ b/blackshades_revenge/Source/GameTick.cpp @@ -0,0 +1,5061 @@ +#include "Game.h" + +#include "SoundFX.h" + + +extern double multiplier; + +extern int thirdperson; + +extern int visions; + +extern Sprites sprites; + + + +extern unsigned int gSourceID[100]; + +extern unsigned int gSampleSet[100]; + +extern Camera camera; + +extern float camerashake; + +extern Fog fog; + +extern int environment; + +extern float precipitationhorz; + +extern float precipitationvert; + +extern float snowdelay; + +extern float precipitationdensity; + +extern float soundscalefactor; + +extern int slomo; + + + +extern int forwardskey; + +extern int backwardskey; + +extern int leftkey; + +extern int rightkey; + +extern int aimkey; + +extern int psychicaimkey; + +extern int psychickey; + + + +extern Decals decals; + +/********************> Tick() <*****/ + +#define maxfallvel 40 + + + +void Game::Splat(int k){ + + if(k!=0||visions==0){ + + person[k].health=0; + + person[k].DoAnimations(k); + + person[k].skeleton.offsetted=0; + + person[k].skeleton.free=1; + + person[k].longdead=1; + + + + person[k].bleeding=1; + + person[k].bleeddelay=1; + + person[k].bjoint1=&person[k].skeleton.joints[person[k].skeleton.jointlabels[head]]; + + person[k].bjoint2=&person[k].skeleton.joints[person[k].skeleton.jointlabels[neck]]; + + + + for(int j=0;jgetFreeSource(gSampleSet[headwhacksound]); + //alSourcei(gSourceID[src_headwhacksound], AL_BUFFER, gSampleSet[headwhacksound]); + alSourcefv(snd, AL_POSITION, gLoc); + alSourcePlay(snd); + + } + +} + + + +void Game::Tick(){ + + if(mainmenu){ + + + + unsigned char theKeyMap[16]; + + GetKeys( ( unsigned long * )theKeyMap ); + + + + if(IsKeyDown(theKeyMap, MAC_SPACE_KEY)){ + + mainmenu=0; + + } + + + + GetMouse(&mouseloc); + + float mousex=mouseloc.h; + + float mousey=mouseloc.v; + + mousex=(float)mouseloc.h*640/screenwidth; + + mousey=480-(float)mouseloc.v*480/screenheight; + + + oldmouseoverbutton=mouseoverbutton; + + mouseoverbutton=0; + + if(mousex>120&&mousex<560&&mousey>235&&mousey<305){ + + mouseoverbutton=1; + + } + + if(mousex>120&&mousex<560&&mousey>112&&mousey<182){ + + mouseoverbutton=2; + + } + + if((Button()&&mouseoverbutton==1&&!gameinprogress&&!oldbutton)||!mainmenuness){ + + if(environment==rainy_environment) + { + ALuint env = SoundFX::inst()->getEnviroSource(gSampleSet[rainsound]); + alSourcef(env, AL_MIN_GAIN, .3); + alSourcePlay(env); + } + + if(environment!=rainy_environment) + { + ALuint env = SoundFX::inst()->getEnviroSource(); + alSourcePause(env); + } + + if(musictoggle) + { + ALuint music = SoundFX::inst()->getMusicSource(); + + alSourceStop(music); + alSourcef(music, AL_MIN_GAIN, 0); + alSourcef(music, AL_MAX_GAIN, 0); + + if(person[0].whichgun==knife)whichsong=knifesong; + + if(person[0].whichgun!=knife)whichsong=shootsong; + + if(type==zombie_type)whichsong=zombiesong; + + alSourcei(music, AL_BUFFER, gSampleSet[whichsong]); + alSourcef(music, AL_PITCH, 1); + alSourcePlay(music); + alSourcef(music, AL_MIN_GAIN, 1); + alSourcef(music, AL_MAX_GAIN, 1); + } + + flashamount=1; + + flashr=1;flashg=1;flashb=1; + + mainmenu=0; + + float gLoc[3]; + getAuralCameraPosition(gLoc); + SoundFX::inst()->playFX(gSampleSet[soulinsound], gLoc, 1.0); + + mission=0; + + InitGame(); + + gameinprogress=1; + + } + + if((Button()&&mouseoverbutton==1&&gameinprogress&&!oldbutton)||!mainmenuness){ + + flashamount=1; + + flashr=1;flashg=1;flashb=1; + + mainmenu=0; + + MoveMouse(oldmouseloc.h,oldmouseloc.v,&mouseloc); + + //if(!visions){ + + ALuint enviro = SoundFX::inst()->getEnviroSource(); + + if(environment==rainy_environment)alSourcePlay(enviro); + + if(environment!=rainy_environment)alSourcePause(enviro); + + if(musictoggle) + { + //alSourceStop(gSourceID[src_songslot]); + //alSourcef(gSourceID[src_songslot], AL_MIN_GAIN, 0); + //alSourcef(gSourceID[src_songslot], AL_MAX_GAIN, 0); + + if(person[0].whichgun==knife)whichsong=knifesong; + + if(person[0].whichgun!=knife)whichsong=shootsong; + + if(type==zombie_type)whichsong=zombiesong; + + ALuint music = SoundFX::inst()->getMusicSource(gSampleSet[whichsong]); + + //alSourcei(music, AL_BUFFER, gSampleSet[whichsong]); + //alSourcef(gSourceID[src_songslot], AL_PITCH, 1); + + alSourcef(music, AL_MIN_GAIN, 1); + alSourcef(music, AL_MAX_GAIN, 1); + alSourcePlay(music); + } + + //} + + float gLoc[3]; + getAuralCameraPosition(gLoc); + SoundFX::inst()->playFX(gSampleSet[soulinsound], gLoc, 1.0); + + if(visions) + { + ALuint vis = SoundFX::inst()->getVisionSource(gSampleSet[visionsound]); + alSourcefv(vis, AL_POSITION, gLoc); + alSourcePlay(vis); + } + + } + + if(Button()&&mouseoverbutton==2&&!gameinprogress&&!oldbutton){ + + flashamount=1; + + flashr=1;flashg=0;flashb=0; + + alSourcePlay(SoundFX::inst()->getFreeSource(gSampleSet[losesound], 1.0)); + + gQuit = true; + + if(score>highscore){ + + highscore=score; + +#ifdef OS9 + std::ofstream opstream(":Data:HighscoreRevenge"); +#else + /* TODO */ + std::ofstream opstream("Data/HighscoreRevenge"); +#endif + opstream << highscore; + + opstream << "\n"; + + opstream << beatgame; + + opstream.close(); + + } + + } + + if(Button()&&mouseoverbutton==2&&gameinprogress&&!oldbutton){ + + flashamount=1; + + flashr=1;flashg=1;flashb=1; + + alSourcePlay(SoundFX::inst()->getFreeSource(gSampleSet[losesound], 1.0)); + + gameinprogress=0; + + if(score>highscore){ + + highscore=score; + +#ifdef OS9 + std::ofstream opstream(":Data:HighscoreRevenge"); +#else + /* TODO */ + std::ofstream opstream("Data/HighscoreRevenge"); +#endif + opstream << highscore; + + opstream << "\n"; + + opstream << beatgame; + + opstream.close(); + + } + + } + + + + if(Button())oldbutton=1; + + if(!Button())oldbutton=0; + + } + + if(!mainmenu){ + + + + + + XYZ facing; + + XYZ flatfacing; + + float speed=10; + + + + if(person[0].health<=0||killedinnocent){ + + losedelay-=multiplier/6; + + } + + + + if(person[0].health>0&&!killedinnocent)timeremaining-=multiplier*25/40; + + if(timeremaining<=0){ + + flashamount=1; + + flashr=0;flashg=1;flashb=0; + + mission++; + + //alSourcePlay(SoundFX::inst()->getFreeSource(gSampleSet[souloutsound], 1.0)); + float gLoc[3]; + getAuralCameraPosition(gLoc); + SoundFX::inst()->playFX(gSampleSet[souloutsound], gLoc, 1.0f); + + // kill vision sound + alSourceStop(SoundFX::inst()->getVisionSource()); + + score+=100+(mission*50); + + if(mission>=nummissions){ + + beatgame=1; + + mainmenu=1; + + gameinprogress=0; + + alSourcePause(SoundFX::inst()->getEnviroSource()); + + + + alSourceStop(SoundFX::inst()->getVisionSource()); + + + if(musictoggle) + { + //alSourceStop(music); + //alSourcef(music, AL_MIN_GAIN, 0); + //alSourcef(music, AL_MAX_GAIN, 0); + + whichsong=mainmenusong; + + ALuint music = SoundFX::inst()->getMusicSource(gSampleSet[whichsong]); + + //alSourceStop(gSourceID[src_songslot]); + + alSourcei(music, AL_BUFFER, gSampleSet[whichsong]); + alSourcef(music, AL_PITCH, 1); + alSourcePlay(music); + alSourcef(music, AL_MIN_GAIN, 1); + alSourcef(music, AL_MAX_GAIN, 1); + } + + if(score>highscore){ + + highscore=score; + +#ifdef OS9 + std::ofstream opstream(":Data:HighscoreRevenge"); +#else + /* TODO */ + std::ofstream opstream("Data/HighscoreRevenge"); +#endif + opstream << highscore; + + opstream << "\n"; + + opstream << beatgame; + + opstream.close(); + + } + + } + + if(!mainmenu){ + + InitGame(); + + if(environment==rainy_environment) + { + ALuint enviro = SoundFX::inst()->getEnviroSource(gSampleSet[rainsound]); + alSourcef(enviro, AL_MIN_GAIN, .3); + alSourcePlay(enviro); + + //alSourcePlay(gSourceID[src_rainsound]); + } + + if(environment!=rainy_environment) + { + alSourcePause(SoundFX::inst()->getEnviroSource()); + //alSourcePause(gSourceID[src_rainsound]); + } + + alSourceStop(SoundFX::inst()->getVisionSource()); + + + if(musictoggle) + { + + if(person[0].whichgun==knife)whichsong=knifesong; + if(person[0].whichgun!=knife)whichsong=shootsong; + + if(type==zombie_type)whichsong=zombiesong; + + ALuint music = SoundFX::inst()->getMusicSource(gSampleSet[whichsong]); + + alSourcef(music, AL_PITCH, 1); + alSourcePlay(music); + alSourcef(music, AL_MIN_GAIN, 1); + alSourcef(music, AL_MAX_GAIN, 1); + } + + } + + } + + if(losedelay<=0){ + + flashamount=1; + + flashr=0;flashg=0;flashb=0; + + if(person[murderer].health>0)score=oldscore-200; + + if(person[murderer].health<=0)score=oldscore-100; + + InitGame(); + + if(musictoggle) + { + if(person[0].whichgun==knife)whichsong=knifesong; + if(person[0].whichgun!=knife)whichsong=shootsong; + if(type==zombie_type)whichsong=zombiesong; + + ALuint music = SoundFX::inst()->getMusicSource(gSampleSet[whichsong]); + + alSourcef(music, AL_PITCH, 1); + alSourcePlay(music); + alSourcef(music, AL_MIN_GAIN, 1); + alSourcef(music, AL_MAX_GAIN, 1); + } + + float gLoc[3]; + getAuralCameraPosition(gLoc); + SoundFX::inst()->playFX(gSampleSet[soulinsound], gLoc, 1.0); + + // kill vision sound + alSourceStop(SoundFX::inst()->getVisionSource()); + + } + + + + unsigned char theKeyMap[16]; + + GetKeys( ( unsigned long * )theKeyMap ); + + + + //Sprites + + sprites.DoStuff(); + + + + //Decals + + decals.DoStuff(); + + + + //Facing + + facing=0; + + facing.z=-1; + + + + facing=DoRotation(facing,-camera.rotation2,0,0); + + facing=DoRotation(facing,0,0-camera.rotation,0); + + + + flatfacing=facing; + + flatfacing.y=0; + + Normalise(&flatfacing); + + + + if(IsKeyDown(theKeyMap, psychickey)&&!oldvisionkey){ + + oldvisionkey=1; + + visions++; + + if(visions==2)visions=0; + + if(visions==0){ + + float rad2deg=56.54866776; + + flashamount=1; + + flashr=1;flashg=1;flashb=1; + + + + if(person[0].playercoords.x!=bodycoords.x||person[0].playercoords.z!=bodycoords.z){ + + XYZ towards; + + towards=person[0].playercoords-bodycoords; + + Normalise(&towards); + + camera.rotation=-asin(0-towards.x); + + camera.rotation*=360/6.28; + + if(towards.z>0)camera.rotation=180-camera.rotation; + + camera.visrotation=camera.rotation; + + camera.oldrotation=camera.rotation; + + camera.oldoldrotation=camera.rotation; + + } + + + + person[0].playercoords=bodycoords; + + person[0].oldplayercoords=bodycoords; + + person[0].velocity=0; + + float gLoc[3]; + getAuralCameraPosition(gLoc); + SoundFX::inst()->playFX(gSampleSet[soulinsound], gLoc, 1.0); + + alSourceStop(SoundFX::inst()->getVisionSource()); + + alSourcef(SoundFX::inst()->getMusicSource(), AL_PITCH, (ALfloat)(1)); + } + + if(visions==1){ + + alSourceStop(SoundFX::inst()->getVisionSource()); + + flashamount=1; + + flashr=1;flashg=0;flashb=0; + + bodycoords=person[0].oldplayercoords; + + //alSourcePlay(SoundFX::inst()->getFreeSource(gSampleSet[souloutsound], 1.0)); + float gLoc[3]; + getAuralCameraPosition(gLoc); + SoundFX::inst()->playFX(gSampleSet[souloutsound], gLoc, 1.0f); + + alSourcef(SoundFX::inst()->getMusicSource(), AL_PITCH, (ALfloat)(.5)); + + ALuint vis = SoundFX::inst()->getVisionSource(gSampleSet[visionsound]); + alSourcefv(vis, AL_POSITION, gLoc); + alSourcePlay(vis); + + } + + } + + if(!IsKeyDown(theKeyMap, psychickey)){ + + oldvisionkey=0; + + } + + + + if(IsKeyDown(theKeyMap, MAC_TAB_KEY)&&!tabkeydown&&debug){ + + thirdperson++; + + if(thirdperson>2)thirdperson=0; + + tabkeydown=1; + + } + + + + if(!IsKeyDown(theKeyMap, MAC_TAB_KEY)) + + tabkeydown=0; + + + + if(IsKeyDown(theKeyMap, aimkey)&&!aimtoggle){ + + person[0].aiming=1-person[0].aiming; + + aimtoggle=1; + + } + + + + if(!IsKeyDown(theKeyMap, aimkey)) + + aimtoggle=0; + + + + if(IsKeyDown(theKeyMap, MAC_R_KEY)&&!reloadtoggle){ + + if(person[0].reloads[person[0].whichgun]>0&&person[0].reloading<=0)person[0].ammo=-1; + + reloadtoggle=1; + + } + + + + if(!IsKeyDown(theKeyMap, MAC_R_KEY)) + + reloadtoggle=0; + + + + if(IsKeyDown(theKeyMap, psychicaimkey)&&!slomokeydown&&slomo==0){ + + //alSourcePlay(SoundFX::inst()->getFreeSource(gSampleSet[souloutsound], 1.0)); + float gLoc[3]; + getAuralCameraPosition(gLoc); + SoundFX::inst()->playFX(gSampleSet[souloutsound], gLoc, 1.0f); + + slomo=2; + + flashamount=.5; + + flashr=1;flashg=0;flashb=0; + + slomokeydown=1; + + score-=20; + + alSourcef(SoundFX::inst()->getMusicSource(), AL_PITCH, (ALfloat)(.5)); + } + + + + if(!IsKeyDown(theKeyMap, psychicaimkey)) + + slomokeydown=0; + + + + //Mouse look + + + + if((person[0].aimamount<=0&&person[0].targetanimation!=crouchanim)){ + + camera.rotation=camera.visrotation; + + camera.rotation2=camera.visrotation2; + + mousesensitivity=usermousesensitivity; + + } + + if(person[0].aimamount>=1&&zoom==0){ + + mousesensitivity=usermousesensitivity*.8; + + } + + if(slomo==2){ + + mousesensitivity*=.6; + + } + +#if 0 // DDOI + GetMouse(&mouseloc); + + if (mouseloc.h>600){MoveMouse(mouseloc.h-500,mouseloc.v,&mouseloc);} + + if (mouseloc.h<100){MoveMouse(mouseloc.h+500,mouseloc.v,&mouseloc);} + + GetMouse(&mouseloc); + + if (mouseloc.v>400){MoveMouse(mouseloc.h,mouseloc.v-300,&mouseloc);} + + if (mouseloc.v<100){MoveMouse(mouseloc.h,mouseloc.v+300,&mouseloc);} + + GetMouse(&mouseloc); + +#else + GetMouseRel(&mouseloc); +#endif + + + +#if 0 // DDOI + oldmouserotation=(oldmouseloc.h/1.3888)*mousesensitivity; + + oldmouserotation2=(oldmouseloc.v/1.3888)*mousesensitivity; +#endif + + mouserotation=(mouseloc.h/1.3888)*mousesensitivity; + + mouserotation2=(mouseloc.v/1.3888)*mousesensitivity; + + if (invertmouse) + { + mouserotation2 *= -1.0f; + } + + + +#if 0 // DDOI + if(abs(oldmouseloc.h-mouseloc.h)<400)camera.rotation+=mouserotation-oldmouserotation; + + if(abs(oldmouseloc.v-mouseloc.v)<200)camera.rotation2+=mouserotation2-oldmouserotation2; + + if(mouseloc.h-oldmouseloc.h>400)camera.rotation+=mouserotation-oldmouserotation-(500/1.3888*mousesensitivity); + + if(mouseloc.h-oldmouseloc.h<-400)camera.rotation+=mouserotation-oldmouserotation+(500/1.3888*mousesensitivity); + + if(mouseloc.v-oldmouseloc.v>200)camera.rotation2+=mouserotation2-oldmouserotation2-(300/1.3888*mousesensitivity); + + if(mouseloc.v-oldmouseloc.v<-200)camera.rotation2+=mouserotation2-oldmouserotation2+(300/1.3888*mousesensitivity); +#else + if(abs(mouseloc.h)<400)camera.rotation+=mouserotation; + if(abs(mouseloc.v)<200)camera.rotation2+=mouserotation2; + if(mouseloc.h>400)camera.rotation+=mouserotation-(500/1.3888*mousesensitivity); + if(mouseloc.h<-400)camera.rotation+=mouserotation+(500/1.3888*mousesensitivity); + + if(mouseloc.v>200)camera.rotation2+=mouserotation2-(300/1.3888*mousesensitivity); + + if(mouseloc.v<-200)camera.rotation2+=mouserotation2+(300/1.3888*mousesensitivity); +#endif + + + + if(camera.rotation2>89){camera.rotation2=89;} + + if(camera.rotation2<-89){camera.rotation2=-89;} + + + + //Smooth + + camera.rotation=(camera.oldoldrotation+((camera.rotation-camera.oldoldrotation)*.7+(camera.oldrotation-camera.oldoldrotation)*.3)); + + camera.rotation2=(camera.oldoldrotation2+((camera.rotation2-camera.oldoldrotation2)*.7+(camera.oldrotation2-camera.oldoldrotation2)*.3)); + + + + if(camera.visrotationcamera.rotation+7)camera.visrotation=camera.rotation+7; + + if(camera.visrotation2camera.rotation2+15)camera.visrotation2=camera.rotation2+15; + + + + if(zoom||person[0].aimamount<=0||person[0].whichgun==nogun||visions||person[0].whichgun==grenade||person[0].whichgun==knife){ + + camera.visrotation=camera.rotation; + + camera.visrotation2=camera.rotation2; + + } + + oldzoom=zoom; + + + + camera.oldoldrotation=camera.oldrotation; + + camera.oldoldrotation2=camera.oldrotation2; + + camera.oldrotation=camera.rotation; + + camera.oldrotation2=camera.rotation2; + + + + //Check collision with buildings + + + + int beginx,endx; + + int beginz,endz; + +// int distsquared; + + XYZ collpoint; + + XYZ move; + +// float howmuchintersect; + + int whichtri; + +// float olddist; + +// XYZ nothing; + + XYZ underpoint; + + XYZ overpoint; + + int pointnum; + + float depth; + + XYZ normalrotated; + +// XYZ pointrotated; + + bool inblock; + + + + + + person[0].playerrotation=180-camera.rotation; + + + + //Check people collisions + + for(int k=0;knum_blocks-1)endx=num_blocks-1; + + endz=(person[k].playercoords.z+block_spacing/2)/block_spacing+1; + + if(endz>num_blocks-1)endz=num_blocks-1; + + + + if(k!=0){ + /* TODO: huh? */ + beginx=person[k].whichblockx; + + beginz=person[k].whichblocky; + + endx=person[k].whichblockx; + + endz=person[k].whichblocky; + + } + + + + if(beginx<=endx&&beginz<=endz) + + for(int i=beginx;i<=endx;i++) + + for(int j=beginz;j<=endz;j++){ + + inblock=0; + + //Ground collision + + move=0; + + move.x=i*block_spacing; + + move.z=j*block_spacing; + + whichtri=sidewalkcollide.LineCheck2(overpoint,underpoint,&collpoint,move,cityrotation[i][j]*90); + + if(whichtri!=-1&&person[k].playercoords.y<=collpoint.y&&person[k].velocity.y<=0){ + + person[k].playercoords.y=collpoint.y; + + person[k].onground=1; + + if(person[k].velocity.y<-maxfallvel)Splat(k); + + else person[k].velocity.y=0; + + } + + if(whichtri!=-1){ + + inblock=1; + + if(k==0){onblockx=i;onblocky=j;} + + } + + //Wall collision + + if(k==0){ + + if(inblock){ + + for(int l=0;l<8;l++){ + + move=0; + + move.x=i*block_spacing; + + move.z=j*block_spacing; + + whichtri=blockwalls[citytype[i][j]].LineCheck3(person[k].oldplayercoords+boundingpoints[l],person[k].playercoords+boundingpoints[l],&collpoint,move,cityrotation[i][j]*90,&depth); + + if(whichtri!=-1){ + + normalrotated=DoRotation(blockwalls[citytype[i][j]].normals[whichtri],0,cityrotation[i][j]*90,0); + + person[k].playercoords+=normalrotated*(-(dotproduct(normalrotated,person[k].playercoords-person[k].oldplayercoords))-depth); + + } + + } + + for(l=0;l<8;l++){ + + pointnum=k+1; + + if(pointnum>3)pointnum=0; + + move=0; + + move.x=i*block_spacing; + + move.z=j*block_spacing; + + whichtri=blockwalls[citytype[i][j]].LineCheck3(person[k].playercoords+boundingpoints[l],person[k].playercoords+boundingpoints[pointnum],&collpoint,move,cityrotation[i][j]*90,&depth); + + if(whichtri!=-1){ + + normalrotated=DoRotation(blockwalls[citytype[i][j]].normals[whichtri],0,cityrotation[i][j]*90,0); + + person[k].playercoords+=normalrotated; + + } + + } + + } + + //Roof collision + + if(inblock&&person[k].playercoords.y>30){ + + if(!person[k].onground){ + + move=0; + + move.x=i*block_spacing; + + move.z=j*block_spacing; + + whichtri=blockroofs[citytype[i][j]].LineCheck2(overpoint,underpoint,&collpoint,move,cityrotation[i][j]*90); + + if(whichtri!=-1&&person[k].playercoords.y<=collpoint.y&&person[k].velocity.y<=0){ + + person[k].playercoords.y=collpoint.y; + + person[k].onground=1; + + if(person[k].velocity.y<-maxfallvel)Splat(k); + + else person[k].velocity.y=0; + + } + + if(whichtri!=-1)inblock=1; + + } + + } + + } + + } + + if(person[k].playercoords.y<=0){ + + person[k].onground=1; + + person[k].playercoords.y=0; + + if(person[k].velocity.y<-maxfallvel)Splat(k); + + else person[k].velocity.y=0; + + if(k==0)onblockx=-1;onblocky=-1; + + } + + // SBF - this is definately in the wrong spot! + //person[k].oldplayercoords=person[k].playercoords; + + } + + } + + } + + + + if(IsKeyDown( theKeyMap, MAC_SPACE_KEY )){ + + if(visions==0&&person[0].targetanimation==joganim&&person[0].currentanimation==joganim&&person[0].backwardsanim==0&&person[0].playerrotation==person[0].playerlowrotation){ + + person[0].targetanimation=diveanim; + + person[0].targetframe=0; + + person[0].target=0; + + person[0].aimamount=0; + + } + + } + + + + //Camera + + camera.oldposition=camera.position; + + camera.targetoffset=0; + + camera.targetoffset.z=-5; + + + + + + //Spawn people + + spawndelay-=multiplier; + + int blockspawnx,blockspawny; + + blockspawnx=0; + + blockspawny=0; + + int cyclenum; + + cyclenum=0; + + while((citypeoplenum[blockspawnx][blockspawny]>=max_people_block&&cyclenum<10)||blockspawnx==0){ + + blockspawnx=((person[0].playercoords.x+block_spacing/2)/block_spacing)+Random()%2; + + blockspawny=((person[0].playercoords.z+block_spacing/2)/block_spacing)+Random()%2; + + cyclenum++; + + } + + if(cyclenum<10){ + + if(spawndelay<0&&numpeople=max_people_block&&cyclenum<10)||blockspawnx==0||(blockspawnx==person[0].whichblockx&&blockspawny==person[0].whichblocky)){ + + blockspawnx=((person[0].playercoords.x+block_spacing/2)/block_spacing)+Random()%2; + + blockspawny=((person[0].playercoords.z+block_spacing/2)/block_spacing)+Random()%2; + + cyclenum++; + + } + + } + + + + person[numpeople].playerrotation=0; + + + + person[numpeople].whichcostume=casualcostumes+abs(Random())%numcasual; + + + + person[numpeople].whichblockx=blockspawnx; + + person[numpeople].whichblocky=blockspawny; + + + + person[numpeople].pathnum=-1; + + person[numpeople].oldpathnum=-1; + + person[numpeople].oldoldpathnum=-1; + + person[numpeople].oldoldoldpathnum=-1; + + while(person[numpeople].pathnum<0||person[numpeople].pathnum>=path.vertexNum||person[numpeople].pathnum==1){ + + person[numpeople].pathnum=Random()%path.vertexNum; + + } + + person[numpeople].pathtarget.x=path.vertex[person[numpeople].pathnum].x; + + person[numpeople].pathtarget.z=path.vertex[person[numpeople].pathnum].z; + + person[numpeople].pathsize=.98+float(abs(Random()%20))/400; + + person[numpeople].pathtarget*=person[numpeople].pathsize; + + person[numpeople].pathtarget.x+=person[numpeople].whichblockx*block_spacing; + + person[numpeople].pathtarget.z+=person[numpeople].whichblocky*block_spacing; + + + + + + person[numpeople].playercoords=person[numpeople].pathtarget; + + person[numpeople].oldplayercoords=person[numpeople].playercoords; + + person[numpeople].skeleton.free=0; + + + + person[numpeople].targetanimation=walkanim; + + if(person[numpeople].type==zombietype)person[numpeople].targetanimation=zombiewalkanim; + + person[numpeople].speed=1; + + person[numpeople].existing=0; + + person[numpeople].speedmult=.8+float(abs(Random()%20))/50; + + person[numpeople].health=100; + + person[numpeople].maxhealth=100; + + person[numpeople].playerrotation2=0; + + + + person[numpeople].lastdistancevictim=200000; + + + + if(person[numpeople].skeleton.broken)person[numpeople].skeleton.Load((char *)":Data:Skeleton:Basic Figure"); + + + + if(numpeople==1)person[numpeople].type=viptype; + + + + person[numpeople].killtarget=-1; + + + + if(person[numpeople].type==eviltype){person[numpeople].existing=1; person[numpeople].pathsize=1.04; person[numpeople].whichgun=nogun; person[numpeople].aiming=1; person[numpeople].killtarget=-1; person[numpeople].speedmult=1+.3*difficulty;} + + if(person[numpeople].type==zombietype){person[numpeople].existing=1; person[numpeople].pathsize=1.04; person[numpeople].whichgun=nogun; person[numpeople].aiming=0; person[numpeople].killtarget=-1; person[numpeople].speedmult=0.7+.2*difficulty;} + + else {person[numpeople].whichgun=nogun; person[numpeople].aiming=0; person[numpeople].killtarget=-1;} + + + + if(person[numpeople].type==viptype){person[numpeople].existing=1;} + + + + + + if(enemystate==2)person[numpeople].killtarget=0; + + + + numpeople++; + + citypeoplenum[blockspawnx][blockspawny]++; + + spawndelay=.1; + + } + + if(spawndelay<0&&numpeople>=max_people){ + + if(cycle>=max_people)cycle=0; + + cyclenum=0; + + while(cyclenum=max_people)cycle=0; + + } + + if(cycle=max_people_block&&cyclenum<10)||blockspawnx==0||(blockspawnx==person[0].whichblockx&&blockspawny==person[0].whichblocky)){ + + blockspawnx=((person[0].playercoords.x+block_spacing/2)/block_spacing)+Random()%2; + + blockspawny=((person[0].playercoords.z+block_spacing/2)/block_spacing)+Random()%2; + + cyclenum++; + + } + + } + + person[cycle].playerrotation=0; + + + + person[cycle].whichcostume=casualcostumes+abs(Random())%numcasual; + + + + citypeoplenum[person[cycle].whichblockx][person[cycle].whichblocky]--; + + person[cycle].whichblockx=blockspawnx; + + person[cycle].whichblocky=blockspawny; + + + + person[cycle].pathnum=-1; + + person[cycle].oldpathnum=-1; + + person[cycle].oldoldpathnum=-1; + + person[cycle].oldoldoldpathnum=-1; + + while(person[cycle].pathnum<0||person[cycle].pathnum>=path.vertexNum||person[cycle].pathnum==1){ + + person[cycle].pathnum=Random()%path.vertexNum; + + } + + person[cycle].pathtarget.x=path.vertex[person[cycle].pathnum].x; + + person[cycle].pathtarget.z=path.vertex[person[cycle].pathnum].z; + + person[cycle].pathsize=.98+float(abs(Random()%20))/400; + + person[cycle].pathtarget*=person[cycle].pathsize; + + person[cycle].pathtarget.x+=person[cycle].whichblockx*block_spacing; + + person[cycle].pathtarget.z+=person[cycle].whichblocky*block_spacing; + + + + person[cycle].playercoords=person[cycle].pathtarget; + + person[cycle].oldplayercoords=person[cycle].playercoords; + + person[cycle].skeleton.free=0; + + + + person[cycle].targetanimation=walkanim; + + if(person[cycle].type==zombietype)person[cycle].targetanimation=zombiewalkanim; + + person[cycle].speed=1; + + person[cycle].existing=0; + + person[cycle].speedmult=.8+float(abs(Random()%20))/50; + + person[cycle].health=100; + + person[cycle].maxhealth=100; + + person[cycle].playerrotation2=0; + + + + if(person[cycle].skeleton.broken)person[cycle].skeleton.Load((char *)":Data:Skeleton:Basic Figure"); + + + + if(enemystate==1)person[cycle].killtarget=-1; + + + + if(person[cycle].type==eviltype){person[cycle].existing=1; person[cycle].pathsize=1.04; person[cycle].whichgun=nogun; person[cycle].aiming=1; person[cycle].killtarget=-1; person[cycle].speedmult=1+.3*difficulty;} + + if(person[cycle].type==zombietype){person[cycle].existing=1; person[cycle].pathsize=1.04; person[cycle].whichgun=nogun; person[cycle].aiming=0; person[cycle].killtarget=-1; person[cycle].speedmult=.7+.2*difficulty;} + + else {person[cycle].whichgun=nogun; person[cycle].aiming=0; person[cycle].killtarget=-1;} + + + + person[cycle].lastdistancevictim=200000; + + + + if(enemystate==2)person[cycle].killtarget=0; + + + + if(numpeople=0){ + + decals.MakeDecal(bloodpool,temp,12,normish, whichtri, &sidewalkcollide, move, cityrotation[person[i].whichblockx][person[i].whichblocky]*90); + + } + + if(whichtri==-1){ + + temp=person[i].skeleton.joints[person[i].skeleton.jointlabels[abdomen]].position; + + temp.y=-.5; + + move=0; + + decals.MakeDecal(bloodpool,temp,12,normish, 0, &sidewalkcollide, move, 0); + + } + + person[i].firstlongdead=1; + + } + + } + + if(person[i].health<100&&person[i].type!=zombietype){ + + person[i].health-=multiplier*120; + + } + + if(person[i].health<100&&person[i].type==zombietype){ + + person[i].health+=multiplier*10; + + if(person[i].health>person[i].maxhealth)person[i].health=person[i].maxhealth; + + } + + if(person[i].health<100&&person[i].type==zombietype&&person[i].skeleton.free==1){ + + person[i].health+=multiplier*10; + + if(person[i].health>person[i].maxhealth)person[i].health=person[i].maxhealth; + + } + + if(person[i].health<40&&person[i].type==zombietype){ + + person[i].speedmult-=multiplier/20; + + if(person[i].speedmult<.6){ + + person[i].speedmult=.6; + + person[i].killtarget=-1; + + } + + } + + if(person[i].health>=40&&person[i].type==zombietype){ + + person[i].speedmult+=multiplier/40; + + if(person[i].speedmult>.7+difficulty*.2){ + + person[i].speedmult=.7+difficulty*.2; + + person[i].killtarget=0; + + } + + } + + + + if(person[i].maxhealth<100&&person[i].type==zombietype){ + + person[i].maxhealth+=multiplier*2; + + if(person[i].maxhealth>100)person[i].maxhealth=100; + + } + + if(person[i].bleeding>0){ + + person[i].bleeding-=multiplier; + + person[i].bleeddelay-=multiplier*10; + + if(person[i].bleeddelay<=0){ + + person[i].bleeddelay=1; + + if(person[i].skeleton.free==0){ + + bleedloc=DoRotation((person[i].bjoint1->position+person[i].bjoint2->position)/2,0,person[i].playerrotation,0)+person[i].playercoords; + + } + + if(person[i].skeleton.free>0){ + + bleedloc=(person[i].bjoint1->position+person[i].bjoint2->position)/2; + + } + + vel=0; + + sprites.MakeSprite(bloodspritedown, .6, 1, .2, .2,bleedloc, vel, 3*person[i].bleeding); + + } + + } + + if(person[i].skeleton.free==0){ + + //Gun + + if(person[i].type==playertype||person[i].type==eviltype){ + + if(i==0){ + + if(person[i].whichgun==shotgun)person[i].recoil-=multiplier*4; + + if(person[i].whichgun==sniperrifle)person[i].recoil-=multiplier*2; + + if(person[i].whichgun==handgun1)person[i].recoil-=multiplier*5; + + if(person[i].whichgun==handgun2)person[i].recoil-=multiplier*5; + + if(person[i].whichgun==assaultrifle)person[i].recoil-=multiplier*10; + + } + + if(i!=0){ + + if(person[i].whichgun==shotgun)person[i].recoil-=multiplier*1; + + if(person[i].whichgun==sniperrifle)person[i].recoil-=multiplier*1; + + if(person[i].whichgun==handgun1)person[i].recoil-=multiplier*2; + + if(person[i].whichgun==handgun2)person[i].recoil-=multiplier*2; + + if(person[i].whichgun==assaultrifle)person[i].recoil-=multiplier*10; + + } + + if(person[i].recoil<0)person[i].recoil=0; + + if(i==0){ + + if(zoom){ + + mousesensitivity=.05*usermousesensitivity; + + if(person[i].targetanimation!=crouchanim||person[i].currentanimation!=crouchanim||person[i].aiming<1){ + + zoom=0; + + } + + if(visions==1)zoom=0; + + } + + if(person[i].currentanimation==crouchanim&&person[i].targetanimation==crouchanim&&person[i].aiming>=1&&person[i].whichgun==sniperrifle){ + + zoom=1; + + if(zoom&&!oldzoom)camera.rotation2-=6; + + } + + if(!zoom)mousesensitivity=1*usermousesensitivity; + + if(person[i].whichgun!=sniperrifle)zoom=0; + + } + + } + + //Zombie eat + + if(i>0&&person[person[i].killtarget].eaten==i&&person[i].targetanimation==zombieeatanim){ + + person[person[i].killtarget].skeleton.joints[person[person[i].killtarget].skeleton.jointlabels[head]].locked=1; + + person[person[i].killtarget].skeleton.joints[person[person[i].killtarget].skeleton.jointlabels[rightshoulder]].locked=1; + + for(int k=0;k<2;k++){ + + person[person[i].killtarget].skeleton.joints[person[person[i].killtarget].skeleton.jointlabels[head]].position=DoRotation(person[i].skeleton.joints[person[i].skeleton.jointlabels[righthand]].position,0,person[i].playerrotation,0)+person[i].playercoords; + + person[person[i].killtarget].skeleton.joints[person[person[i].killtarget].skeleton.jointlabels[head]].velocity=0; + + person[person[i].killtarget].skeleton.joints[person[person[i].killtarget].skeleton.jointlabels[rightshoulder]].position=DoRotation(person[i].skeleton.joints[person[i].skeleton.jointlabels[lefthand]].position,0,person[i].playerrotation,0)+person[i].playercoords; + + person[person[i].killtarget].skeleton.joints[person[person[i].killtarget].skeleton.jointlabels[rightshoulder]].velocity=0; + + person[person[i].killtarget].skeleton.DoConstraints(); + + person[person[i].killtarget].skeleton.DoConstraints(&blocksimplecollide[citytype[person[i].whichblockx][person[i].whichblocky]],&move,cityrotation[person[i].whichblockx][person[i].whichblocky]*90); + + } + + person[person[i].killtarget].skeleton.joints[person[person[i].killtarget].skeleton.jointlabels[head]].locked=0; + + person[person[i].killtarget].skeleton.joints[person[person[i].killtarget].skeleton.jointlabels[rightshoulder]].locked=0; + + + + person[person[i].killtarget].longdead=1; + + } + + + + if(i>0&&enemystate!=1&&person[i].type==zombietype&&person[i].speedmult>.7){ + + if(findDistancefast(person[i].playercoords,person[0].playercoords)<20000)person[i].killtarget=0; + + else person[i].killtarget=-1; + + } + + if(i>0&&enemystate!=1&&person[i].type==zombietype&&person[i].speedmult<.7){ + + person[i].killtarget=-1; + + } + + + + bool realcheck = false; + + //Pathfinding + if(i>0&&person[i].targetanimation!=getupfrontanim&&person[i].targetanimation!=thrownanim&&person[i].targetanimation!=getupbackanim&&person[i].currentanimation!=getupfrontanim&&person[i].currentanimation!=getupbackanim){ + + person[i].pathcheckdelay-=multiplier; + + // Realcheck tells us + // a) we've got close to the end of our path or + // b) we're moving away from our target + realcheck=(abs(person[i].playercoords.x-person[i].pathtarget.x)<1&&abs(person[i].playercoords.z-person[i].pathtarget.z)<1) + ||findDistancefast(person[i].playercoords,person[i].pathtarget)>findDistancefast(person[i].oldplayercoords,person[i].pathtarget); + + if(person[i].targetanimation==idleanim&&person[i].killtargetvisible==0){ + + person[i].targetanimation=walkanim; + + if(person[i].type==zombietype)person[i].targetanimation=zombiewalkanim; + + realcheck=1; + + } + + if((realcheck||((person[i].killtarget>-1&&person[i].type!=civiliantype)&&person[i].pathcheckdelay<=0)||person[i].killtargetvisible)){ + + person[i].pathcheckdelay=1.2; + + if((person[i].killtarget==-1||person[i].type==civiliantype)&&!person[i].running){ + + person[i].killtargetvisible=0; + + leastdistance=2000000; + + for(int j=0;j=0&&closesttargetnum_blocks-1)endx=num_blocks-1; + + endz=person[i].whichblocky+2; + + if(endz>num_blocks-1)endz=num_blocks-1; + + + + leastdistance=2000000; + + for(int l=beginx;l<=endx;l++){ + + for(int m=beginx;m<=endx;m++){ + + for(int j=0;jfindDistancefast(person[i].playercoords,person[person[i].killtarget].playercoords)&&j!=1&&blocksimple.LineCheck2(person[i].playercoords,person[i].pathtarget,&blah,move,cityrotation[person[i].whichblockx][person[i].whichblocky])==-1&&blocksimple.LineCheck2(person[i].playercoords,person[i].pathtarget,&blah,move,cityrotation[l][m])==-1){ + + person[i].lastdistancevictim=findDistancefast(person[i].pathtarget,person[person[i].killtarget].playercoords); + + leastdistance=findDistancefast(person[i].playercoords,person[i].pathtarget); + + closesttarget=j; + + finaltarget=person[i].pathtarget; + + person[i].whichblockx=l; + + person[i].whichblocky=m; + + } + + } + + } + + } + + } + + if(closesttarget!=-1){ + + person[i].pathnum=closesttarget; + + person[i].pathtarget=finaltarget; + + } + + } + + } + + //Assassin + + if((person[i].killtarget>-1&&person[i].type!=civiliantype)&&!person[i].running){ + + //Dead target? + + if(person[person[i].killtarget].health<=0&&person[i].type==eviltype){ + + person[i].playerrotation2=0; + + person[i].whichgun=nogun; + + person[i].targetanimation=walkanim; + + person[i].lastdistancevictim=200000; + + person[i].pathnum=-1; + + enemystate=1; + + person[i].killtarget=-1; + + realcheck=1; + + } + + if(person[i].type==zombietype&&person[person[i].killtarget].health<=0){ + + if(person[person[i].killtarget].eaten!=i){ + + person[i].playerrotation2=0; + + person[i].targetanimation=zombiewalkanim; + + person[i].lastdistancevictim=200000; + + person[i].pathnum=-1; + + realcheck=1; + + person[i].killtarget=-1; + + } + + if(person[person[i].killtarget].eaten==i&&person[i].targetanimation!=zombieeatanim){ + + person[i].targetanimation=zombieeatanim; + + person[i].targetframe=0; + + person[i].target=0; + + } + + enemystate=1; + + } + + if(person[person[i].killtarget].health>0){ + + if(person[person[i].killtarget].skeleton.free){ + + person[person[i].killtarget].playercoords=person[person[i].killtarget].averageloc; + + } + + + + //If pathfind + + if(realcheck){ + + leastdistance=2000000; + + person[i].lastdistancevictim=2000000; + + closesttarget=-1; + + //Check best path + + for(int j=0;jnum_blocks-1)endx=num_blocks-1; + + endz=person[i].whichblocky+2; + + if(endz>num_blocks-1)endz=num_blocks-1; + + + + leastdistance=2000000; + + for(int l=beginx;l<=endx;l++){ + + for(int m=beginx;m<=endx;m++){ + + if(l!=person[i].whichblockx||m!=person[i].whichblocky){ + + for(int j=0;j30000)person[i].killtargetvisible=0; + + if(person[i].killtarget==0&&visions==1)person[i].killtargetvisible=0; + + if(person[i].killtargetvisible){ + + beginx=person[i].whichblockx-2; + + if(beginx<0)beginx=0; + + beginz=person[i].whichblocky-2; + + if(beginz<0)beginz=0; + + + + endx=person[i].whichblockx+2; + + if(endx>num_blocks-1)endx=num_blocks-1; + + endz=person[i].whichblocky+2; + + if(endz>num_blocks-1)endz=num_blocks-1; + + + + for(int l=beginx;l<=endx;l++){ + + for(int m=beginx;m<=endx;m++){ + + move.x=l*block_spacing; + + move.z=m*block_spacing; + + move.y=-3; + + if(person[i].killtargetvisible){ + + if(blocksimple.LineCheck2(person[i].playercoords,person[person[i].killtarget].playercoords,&blah,move,cityrotation[l][m])!=-1) + + { + + person[i].killtargetvisible=0; + + } + + } + + } + + } + + } + + if(person[i].type==eviltype){ + + if(!person[i].killtargetvisible&&person[i].targetanimation==idleanim){ + + person[i].targetanimation=joganim; + + } + + if(!person[i].killtargetvisible){ + + person[i].aiming=0; + + } + + if(person[i].killtargetvisible){ + + person[i].onpath=0; + + person[i].lastdistancevictim=200000; + + person[i].pathnum=-1; + + if(person[i].whichgun==nogun){ + + person[i].whichgun=possiblegun[abs(Random()%numpossibleguns)]; + + person[i].reloads[person[i].whichgun]=1; + + if(person[i].whichgun==knife)person[i].speedmult=.8+.5*difficulty; + + } + + if(person[i].aiming==0)person[i].shotdelay=shotdelayamount/difficulty; + + person[i].aiming=1; + + if(person[i].reloading>0)person[i].aiming=0; + + if(person[i].whichgun==handgun1||person[i].whichgun==handgun2)person[i].playerrotation2=-10; + + if(person[i].whichgun==assaultrifle||person[i].whichgun==sniperrifle||person[i].whichgun==shotgun)person[i].playerrotation2=20; + + tooclose=1300; + + toofar=3000; + + if(person[i].whichgun==shotgun){ + + tooclose=1400; + + toofar=5000; + + } + + if(person[i].whichgun==assaultrifle){ + + tooclose=5000; + + toofar=9000; + + } + + if(person[i].whichgun==sniperrifle){ + + tooclose=10000; + + toofar=20000; + + } + + if(person[i].whichgun==knife){ + + tooclose=20; + + toofar=20000; + + } + + if(findDistancefast(person[i].playercoords, person[person[i].killtarget].playercoords)>toofar) + + person[i].targetanimation=joganim; + + if((findDistancefast(person[i].playercoords, person[person[i].killtarget].playercoords)<=tooclose&&person[person[i].killtarget].skeleton.free==0)||(tooclose>200&&findDistancefast(person[i].playercoords, person[person[i].killtarget].playercoords)<=200)||(tooclose<=200&&findDistancefast(person[i].playercoords, person[person[i].killtarget].playercoords)playFX(gSampleSet[knifeslashsound], gLoc); + + person[person[i].killtarget].bjoint1=&person[person[i].killtarget].skeleton.joints[person[person[i].killtarget].skeleton.jointlabels[neck]]; + + person[person[i].killtarget].bjoint2=&person[person[i].killtarget].skeleton.joints[person[person[i].killtarget].skeleton.jointlabels[neck]]; + + person[person[i].killtarget].bleeding=1; + + person[person[i].killtarget].bleeddelay=1; + + person[person[i].killtarget].health-=20; + + person[person[i].killtarget].targetanimation=chestpainanim; + + person[person[i].killtarget].targetframe=0; + + person[person[i].killtarget].target=0; + + person[person[i].killtarget].longdead=1; + + } + + } + + } + + finaltarget=person[person[i].killtarget].playercoords; + + } + + } + + if(person[i].type==zombietype&&person[person[i].killtarget].health>0){ + + if(!person[i].killtargetvisible&&person[i].targetanimation==idleanim){ + + person[i].targetanimation=zombiejoganim; + + } + + if(!person[i].killtargetvisible){ + + person[i].aiming=0; + + } + + if(person[i].killtargetvisible){ + + person[i].onpath=0; + + person[i].lastdistancevictim=200000; + + person[i].pathnum=-1; + + if(person[i].aiming==0)person[i].shotdelay=shotdelayamount/difficulty; + + if(findDistancefast(person[i].playercoords, person[person[i].killtarget].playercoords)>20||person[i].targetanimation!=idleanim) + + person[i].targetanimation=zombiejoganim; + + if(findDistancefast(person[i].playercoords, person[person[i].killtarget].playercoords)<=20){ + + murderer=i; + + person[person[i].killtarget].health=0; + + person[person[i].killtarget].eaten=i; + + } + + finaltarget=person[person[i].killtarget].playercoords; + + } + + } + + if(person[i].killtargetvisible||realcheck)person[i].pathtarget=finaltarget; + + if(realcheck)person[i].lastdistancevictim=findDistancefast(person[i].pathtarget,person[person[i].killtarget].playercoords); + + } + + } + + + + if(person[i].targetanimation!=zombieeatanim||person[i].type!=zombietype){ + + towards=person[i].playercoords-person[i].pathtarget; + + Normalise(&towards); + + person[i].playerrotation=asin(0-towards.x)*360/6.28; + + if(towards.z>0)person[i].playerrotation=180-person[i].playerrotation; + + } + + } + + } + + person[i].whichblockx=((person[i].playercoords.x+block_spacing/2)/block_spacing); + + person[i].whichblocky=((person[i].playercoords.z+block_spacing/2)/block_spacing); + + + + if(!person[i].onground)person[i].velocity.y+=multiplier*gravity; + + if(!person[i].onground&&(i!=0||visions!=1))person[i].playercoords+=person[i].velocity*multiplier; + + //Death by bleeding/shock + + if(person[i].health<=0){ + + person[i].skeleton.offsetted=0; + + person[i].skeleton.free=1; + + person[i].longdead=1; + + for(int j=0;j0){ + + person[i].whichblockx=((person[i].skeleton.joints[0].position.x+block_spacing/2)/block_spacing); + + person[i].whichblocky=((person[i].skeleton.joints[0].position.z+block_spacing/2)/block_spacing); + + move=0; + + move.x=person[i].whichblockx*block_spacing; + + move.z=person[i].whichblocky*block_spacing; + + person[i].skeleton.DoGravity(); + + if(person[i].averageloc.y<=50)person[i].skeleton.DoConstraints(&blocksimplecollide[citytype[person[i].whichblockx][person[i].whichblocky]],&move,cityrotation[person[i].whichblockx][person[i].whichblocky]*90); + + if(person[i].averageloc.y>50)person[i].skeleton.DoConstraints(&blockcollide[citytype[person[i].whichblockx][person[i].whichblocky]],&move,cityrotation[person[i].whichblockx][person[i].whichblocky]*90); + + person[i].oldaverageloc=person[i].averageloc; + + person[i].averageloc=0; + + for(int j=0;j0)person[i].DrawSkeleton(i); + + if(findDistancefast(person[i].averageloc,person[i].oldaverageloc)<.2*multiplier)person[i].longdead-=multiplier/2; + + } + + if(person[i].skeleton.free==1&&person[i].longdead<=0&&person[i].health>0&&person[i].longdead!=-1){ + + person[i].longdead=1; + + person[i].skeleton.free=0; + + person[i].currentanimation=lyinganim; + + person[i].target=0; + + person[i].targetframe=0; + + //Get up from front or back? + + if(person[i].skeleton.forward.y>0) + + person[i].targetanimation=getupfrontanim; + + else + + person[i].targetanimation=getupbackanim; + + //Find playercoords + + person[i].playercoords=person[i].averageloc; + + for(int j=0;jperson[i].playercoords.y)person[i].playercoords.y=person[i].skeleton.joints[j].position.y; + + } + + //Find orientation + + XYZ firsttop=person[i].skeleton.joints[person[i].skeleton.jointlabels[neck]].position-person[i].skeleton.joints[person[i].skeleton.jointlabels[groin]].position; + + Normalise(&firsttop); + + person[i].playerrotation=acos(0-firsttop.z); + + person[i].playerrotation*=360/6.28; + + if(0>firsttop.x)person[i].playerrotation=360-person[i].playerrotation; + + person[i].playerrotation*=-1; + + person[i].playervelocity=0; + + if(person[i].targetanimation==getupfrontanim)person[i].playerrotation+=180; + + for(j=0;j0&&person[0].reloading<=0&&person[0].attackframe<0&&person[0].targetanimation!=crouchanim){ + + if(person[0].grenphase==0){ + + XYZ soundsource=DoRotation(person[0].skeleton.joints[person[0].skeleton.jointlabels[righthand]].position,0,person[0].playerrotation,0)+person[0].playercoords; + + float gLoc[3]; + + gLoc[0]=soundsource.x/soundscalefactor; + gLoc[1]=soundsource.y/soundscalefactor; + gLoc[2]=soundsource.z/soundscalefactor; + + + ALuint snd = SoundFX::inst()->getFreeSource(gSampleSet[pinpullsound]); + //alSourcei(gSourceID[src_pinpullsound], AL_BUFFER, gSampleSet[pinpullsound]); + alSourcefv(snd, AL_POSITION, gLoc); + alSourcePlay(snd); + + person[0].grenphase=1; + + } + + } + + if((!Button())&&person[0].whichgun==grenade){ + + if(person[0].grenphase==1){ + + person[0].grenphase=0; + + person[0].attackframe=0; + + person[0].attacktarget=0; + + person[0].killtarget=0; + + } + + } + + if(person[0].targetanimation==crouchanim){ + + if(person[0].grenphase==1){ + + person[0].grenphase=0; + + XYZ soundsource=DoRotation(person[0].skeleton.joints[person[0].skeleton.jointlabels[righthand]].position,0,person[0].playerrotation,0)+person[0].playercoords; + + float gLoc[3]; + + gLoc[0]=soundsource.x/soundscalefactor; + + gLoc[1]=soundsource.y/soundscalefactor; + + gLoc[2]=soundsource.z/soundscalefactor; + + ALuint snd = SoundFX::inst()->getFreeSource(gSampleSet[pinreplacesound]); + //alSourcei(gSourceID[src_pinreplacesound], AL_BUFFER, gSampleSet[pinreplacesound]); + alSourcefv(snd, AL_POSITION, gLoc); + + alSourcePlay(snd); + + } + + } + + + + //Get gun + + int temp; + + int temp2; + + bool switched=0; + + if(Button()&&!oldbutton&&(person[0].aiming==0||person[0].whichgun==grenade||person[0].whichgun==nogun||person[0].whichgun==knife)&&person[0].currentanimation==crouchanim){ + + for(int i=0;igetFreeSource(gSampleSet[clicksound]); + //alSourcei(gSourceID[src_clicksound], AL_BUFFER, gSampleSet[clicksound]); + alSourcefv(snd, AL_POSITION, gLoc); + alSourcePlay(snd); + + + + temp=person[0].whichgun; + + temp2=person[0].ammo; + + person[0].whichgun=person[i].whichgun; + + person[0].ammo=person[i].ammo; + + person[i].whichgun=temp; + + person[i].ammo=temp2; + + person[0].aiming=1; + + person[0].aimamount=0; + + + + switched=1; + + } + + } + + } + + + + //Throw + + if(Button()&&person[0].attackframe<0&&((person[0].whichgun==nogun||person[0].aiming==0)&&person[0].whichgun!=knife)&&person[0].currentanimation!=crouchanim&&person[0].targetanimation!=crouchanim&&person[0].targetanimation!=throwanim&&visions==0){ + + if(person[0].targetanimation==idleanim||person[0].targetanimation==walkanim){ + + bool attacking=0; + + person[0].killtarget=-1; + + float closedistance=-1; + + for(int i=1;i1||(person[0].attackframe>=0&&person[0].currentanimation==joganim)){ + + if(person[person[0].killtarget].skeleton.free<1&&person[0].killtarget!=0&&(person[0].aiming<1||person[0].whichgun==nogun||person[0].whichgun==knife||person[0].targetanimation==joganim)){ + + float gLoc[3]; + + gLoc[0]=(camera.position.x+((person[0].playercoords.x+flatfacing.x)-camera.position.x)/2)/soundscalefactor; + + gLoc[1]=(camera.position.y+((person[0].playercoords.y+flatfacing.y)-camera.position.y)/2)/soundscalefactor; + + gLoc[2]=(camera.position.z+((person[0].playercoords.z+flatfacing.z)-camera.position.z)/2)/soundscalefactor; + + if(person[person[0].killtarget].type!=zombietype) + + { + + if(person[0].whichgun!=knife){ + + + ALuint snd = SoundFX::inst()->getFreeSource(gSampleSet[headwhacksound]); + //alSourcei(gSourceID[src_headwhacksound], AL_BUFFER, gSampleSet[headwhacksound]); + alSourcefv(snd, AL_POSITION, gLoc); + alSourcePlay(snd); + + } + + if(person[0].whichgun==knife){ + + ALuint snd = SoundFX::inst()->getFreeSource(gSampleSet[knifeslashsound]); + //alSourcei(gSourceID[src_knifeslashsound], AL_BUFFER, gSampleSet[knifeslashsound]); + alSourcefv(snd, AL_POSITION, gLoc); + alSourcePlay(snd); + + person[person[0].killtarget].bjoint1=&person[person[0].killtarget].skeleton.joints[person[person[0].killtarget].skeleton.jointlabels[neck]]; + + person[person[0].killtarget].bjoint2=&person[person[0].killtarget].skeleton.joints[person[person[0].killtarget].skeleton.jointlabels[neck]]; + + person[person[0].killtarget].bleeding=1; + + person[person[0].killtarget].bleeddelay=1; + + person[0].bjoint1=&person[0].skeleton.joints[person[0].skeleton.jointlabels[righthand]]; + + person[0].bjoint2=&person[0].skeleton.joints[person[0].skeleton.jointlabels[righthand]]; + + person[0].bleeding=1; + + person[0].bleeddelay=1; + + velocity=DoRotation(flatfacing,0,70,0)*50+person[0].velocity*2; + + velocity.y+=30; + + sprites.MakeSprite(bloodspritedown, .8, 1, .2, .2,DoRotation(person[person[0].killtarget].skeleton.joints[person[person[0].killtarget].skeleton.jointlabels[neck]].position,0,person[person[0].killtarget].playerrotation,0)+person[person[0].killtarget].playercoords, velocity*.3, 2); + + sprites.MakeSprite(bloodspritedown, .8, 1, .2, .2,DoRotation(person[person[0].killtarget].skeleton.joints[person[person[0].killtarget].skeleton.jointlabels[neck]].position,0,person[person[0].killtarget].playerrotation,0)+person[person[0].killtarget].playercoords, velocity*.2, 3); + + sprites.MakeSprite(bloodspritedown, .8, 1, .2, .2,DoRotation(person[person[0].killtarget].skeleton.joints[person[person[0].killtarget].skeleton.jointlabels[neck]].position,0,person[person[0].killtarget].playerrotation,0)+person[person[0].killtarget].playercoords, velocity*.1, 4); + + } + + person[person[0].killtarget].health-=100; + + person[person[0].killtarget].skeleton.free=1; + + person[person[0].killtarget].longdead=1; + + for(int j=0;jgetFreeSource(gSampleSet[headwhacksound]); + //alSourcei(gSourceID[src_headwhacksound], AL_BUFFER, gSampleSet[headwhacksound]); + alSourcefv(snd, AL_POSITION, gLoc); + alSourcePlay(snd); + + } + + if(person[0].whichgun==knife){ + + ALuint snd = SoundFX::inst()->getFreeSource(gSampleSet[knifeslashsound]); + //alSourcei(gSourceID[src_knifeslashsound], AL_BUFFER, gSampleSet[knifeslashsound]); + alSourcefv(snd, AL_POSITION, gLoc); + alSourcePlay(snd); + + person[person[0].killtarget].bjoint1=&person[person[0].killtarget].skeleton.joints[person[person[0].killtarget].skeleton.jointlabels[neck]]; + + person[person[0].killtarget].bjoint2=&person[person[0].killtarget].skeleton.joints[person[person[0].killtarget].skeleton.jointlabels[neck]]; + + person[person[0].killtarget].bleeding=1; + + person[person[0].killtarget].bleeddelay=1; + + person[0].bjoint1=&person[0].skeleton.joints[person[0].skeleton.jointlabels[righthand]]; + + person[0].bjoint2=&person[0].skeleton.joints[person[0].skeleton.jointlabels[righthand]]; + + person[0].bleeding=1; + + person[0].bleeddelay=1; + + velocity=DoRotation(flatfacing,0,70,0)*50+person[0].velocity*2; + + velocity.y+=30; + + sprites.MakeSprite(bloodspritedown, .8, 1, .2, .2,DoRotation(person[person[0].killtarget].skeleton.joints[person[person[0].killtarget].skeleton.jointlabels[neck]].position,0,person[person[0].killtarget].playerrotation,0)+person[person[0].killtarget].playercoords, velocity*.3, 2); + + sprites.MakeSprite(bloodspritedown, .8, 1, .2, .2,DoRotation(person[person[0].killtarget].skeleton.joints[person[person[0].killtarget].skeleton.jointlabels[neck]].position,0,person[person[0].killtarget].playerrotation,0)+person[person[0].killtarget].playercoords, velocity*.2, 3); + + sprites.MakeSprite(bloodspritedown, .8, 1, .2, .2,DoRotation(person[person[0].killtarget].skeleton.joints[person[person[0].killtarget].skeleton.jointlabels[neck]].position,0,person[person[0].killtarget].playerrotation,0)+person[person[0].killtarget].playercoords, velocity*.1, 4); + + } + + person[person[0].killtarget].health-=200; + + person[person[0].killtarget].maxhealth-=20; + + person[person[0].killtarget].skeleton.free=1; + + person[person[0].killtarget].longdead=1; + + for(int j=0;jgetFreeSource(gSampleSet[headwhacksound]); + //alSourcei(gSourceID[src_headwhacksound], AL_BUFFER, gSampleSet[headwhacksound]); + alSourcefv(snd, AL_POSITION, gLoc); + alSourcePlay(snd); + + person[i].skeleton.free=1; + + person[i].longdead=1; + + for(int j=0;j0&&person[j].reloading<=0&&person[j].targetanimation!=joganim){ + + if(Button()&&!oldbutton&&j==0)firing=1; + + if(j!=0)firing=0; + + if(j!=0&&person[j].whichgun!=nogun&&person[j].whichgun!=knife&&person[j].killtargetvisible&&person[j].shotdelay<0)firing=1; + + if(j!=0&&person[j].whichgun!=nogun&&person[j].whichgun!=knife&&person[j].killtargetvisible&&person[j].shotdelay>0)person[j].shotdelay-=multiplier*.9; + + if(person[j].skeleton.free==1||person[j].targetanimation==getupfrontanim||person[j].targetanimation==getupbackanim)person[j].shotdelay=shotdelayamount/difficulty; + + if(j!=0&&person[j].whichgun!=nogun&&person[j].whichgun!=knife&&person[j].killtargetvisible)person[j].aiming=1; + + if(person[0].whichgun!=assaultrifle)oldbutton=1; + + } + + if(person[j].ammo==0&&person[j].reloads[person[j].whichgun]>0){ + + person[j].ammo=-1; + + person[j].aiming=0; + + firing=0; + + } + + if(person[0].ammo<=0&&Button()&&!oldbutton&&person[0].targetanimation!=joganim&&person[0].whichgun!=nogun&&person[0].whichgun!=knife&&person[0].whichgun!=grenade&&person[0].aiming){ + + oldbutton=1; + + float gLoc[3]; + + gLoc[0]=person[0].playercoords.x/soundscalefactor; + + gLoc[1]=person[0].playercoords.y/soundscalefactor; + + gLoc[2]=person[0].playercoords.z/soundscalefactor; + + + ALuint snd = SoundFX::inst()->getFreeSource(gSampleSet[clicksound]); + //alSourcei(gSourceID[src_clicksound], AL_BUFFER, gSampleSet[clicksound]); + alSourcefv(snd, AL_POSITION, gLoc); + alSourcePlay(snd); + } + + if(j==0&&visions==1&&firing){ + + firing=0; + + //alSourcePlay(gSourceID[src_soulinsound]); + float gLoc[3]; + getAuralCameraPosition(gLoc); + SoundFX::inst()->playFX(gSampleSet[soulinsound], gLoc, 1.0); + + } + + if(person[j].aimamount<1)firing=0; + + if(firing){ + + if(person[j].whichgun==handgun1||person[j].whichgun==handgun2)inaccuracy=8; + + if(person[j].whichgun==assaultrifle)inaccuracy=6; + + if(person[j].whichgun==sniperrifle)inaccuracy=2; + + if(person[j].whichgun==shotgun)inaccuracy=6; + + if(person[person[j].killtarget].skeleton.free==1)inaccuracy*=3; + + + + person[j].shotdelay=shotdelayamount/difficulty; + + if(person[j].aiming>=1&&person[j].recoil<=0){ + + //Firing + + person[j].litup=1; + + person[j].recoil=1; + + XYZ end, aim, oldend; + + HitStruct hitstruct,temphitstruct; + + float olddistance = 0.0f; + + float distance = 0.0f; + + float totalarea = 0.0f; + + int whichhit=-1; + + if(person[j].whichgun==shotgun)numshots=7; + + if(person[j].whichgun!=shotgun)numshots=1; + + if(person[j].whichgun!=grenade)person[j].ammo--; + + for(int p=0;pplayFX(gSampleSet[riflesound], gLoc); + + //alSourcei(gSourceID[src_riflesound], AL_BUFFER, gSampleSet[riflesound]); + + + if(j==0){ + + if(person[j].currentanimation!=crouchanim)camera.rotation2-=7; + + if(person[j].currentanimation==crouchanim)camera.rotation2-=3; + + } + + } + + if(person[j].whichgun==shotgun){ + + start=person[j].playercoords+DoRotation(person[j].skeleton.joints[(person[j].skeleton.jointlabels[lefthand])].position,0,person[j].playerrotation,0); + + float gLoc[3]; + + + + start-=DoRotation(DoRotation(DoRotation(aim,0,-person[j].playerrotation,0),90,0,0),0,person[j].playerrotation,0)*.35; + + + + if(p==numshots-1){ + + gLoc[0]=(camera.position.x+(start.x-camera.position.x)/4)/soundscalefactor; + gLoc[1]=(camera.position.y+(start.y-camera.position.y)/4)/soundscalefactor; + gLoc[2]=(camera.position.z+(start.z-camera.position.z)/4)/soundscalefactor; + + SoundFX::inst()->playFX(gSampleSet[shotgunsound], gLoc); + //alSourcei(gSourceID[src_shotgunsound], AL_BUFFER, gSampleSet[shotgunsound]); + + if(j==0){ + + if(person[j].currentanimation!=crouchanim)camera.rotation2-=7; + + if(person[j].currentanimation==crouchanim)camera.rotation2-=3; + + } + + } + + } + + if(person[j].whichgun==handgun1){ + + start=person[j].playercoords+DoRotation(person[j].skeleton.joints[(person[j].skeleton.jointlabels[rightwrist])].position,0,person[j].playerrotation,0); + + start-=DoRotation(DoRotation(DoRotation(aim,0,-person[j].playerrotation,0),90,0,0),0,person[j].playerrotation,0)*.55; + + + + float gLoc[3]; + + + + gLoc[0]=(camera.position.x+(start.x-camera.position.x)/4)/soundscalefactor; + gLoc[1]=(camera.position.y+(start.y-camera.position.y)/4)/soundscalefactor; + gLoc[2]=(camera.position.z+(start.z-camera.position.z)/4)/soundscalefactor; + + SoundFX::inst()->playFX(gSampleSet[pistol1sound], gLoc); + //alSourcei(gSourceID[src_pistol1sound], AL_BUFFER, gSampleSet[pistol1sound]); + + if(j==0){ + + if(person[j].currentanimation!=crouchanim)camera.rotation2-=6; + + if(person[j].currentanimation==crouchanim)camera.rotation2-=4; + + } + + } + + if(person[j].whichgun==handgun2){ + + start=person[j].playercoords+DoRotation(person[j].skeleton.joints[(person[j].skeleton.jointlabels[rightwrist])].position,0,person[j].playerrotation,0); + + start-=DoRotation(DoRotation(DoRotation(aim,0,-person[j].playerrotation,0),90,0,0),0,person[j].playerrotation,0)*.55; + + + + float gLoc[3]; + + + + gLoc[0]=(camera.position.x+(start.x-camera.position.x)/4)/soundscalefactor; + gLoc[1]=(camera.position.y+(start.y-camera.position.y)/4)/soundscalefactor; + gLoc[2]=(camera.position.z+(start.z-camera.position.z)/4)/soundscalefactor; + + SoundFX::inst()->playFX(gSampleSet[pistol2sound], gLoc); + //alSourcei(gSourceID[src_pistol2sound], AL_BUFFER, gSampleSet[pistol2sound]); + + if(j==0){ + + if(person[j].currentanimation!=crouchanim)camera.rotation2-=5; + + if(person[j].currentanimation==crouchanim)camera.rotation2-=3; + + } + + } + + if(person[j].whichgun==assaultrifle){ + + start=person[j].playercoords+DoRotation(person[j].skeleton.joints[(person[j].skeleton.jointlabels[lefthand])].position,0,person[j].playerrotation,0); + + start-=DoRotation(DoRotation(DoRotation(aim,0,-person[j].playerrotation,0),90,0,0),0,person[j].playerrotation,0)*.25; + + + + float gLoc[3]; + + gLoc[0]=(camera.position.x+(start.x-camera.position.x)/4)/soundscalefactor; + gLoc[1]=(camera.position.y+(start.y-camera.position.y)/4)/soundscalefactor; + gLoc[2]=(camera.position.z+(start.z-camera.position.z)/4)/soundscalefactor; + + SoundFX::inst()->playFX(gSampleSet[machinegunsound], gLoc); + //alSourcei(gSourceID[src_machinegunsound], AL_BUFFER, gSampleSet[machinegunsound]); + + if(j==0){ + + if(person[j].currentanimation!=crouchanim){ + + camera.rotation2-=2.3; + + camera.rotation+=(float)(Random()%100)/50; + + } + + if(person[j].currentanimation==crouchanim){ + + camera.rotation2-=1.5; + + camera.rotation+=(float)(Random()%100)/60; + + } + + } + + } + + end=start+aim*1000; + + if(debug){ + + if(IsKeyDown(theKeyMap, MAC_G_KEY)&&j==0){ + + sprites.MakeSprite(grenadesprite, 1, 1, 1, 1, start, aim*200, 1.01); + + } + + } + + if(!IsKeyDown(theKeyMap, MAC_G_KEY)||j!=0||!debug){ + + int bulletstrength=1; + + int firstpass=-1; + + bool penetrate; + + for(int m=0;mnum_blocks-1)endx=num_blocks-1; + + endz=(person[j].playercoords.z+block_spacing/2)/block_spacing+3; + + if(endz>num_blocks-1)endz=num_blocks-1; + + + + if(beginx.9)bulletstrength=2; + + } + + } + + wallhit=0; + + wallhit.x=camera.position.x; + + wallhit.z=camera.position.z; + + whichtri=Bigstreet.LineCheck2(start,end,&wallhit,wallhit,0); + + if(whichtri!=-1){ + + end.y-=.5; + + end=wallhit; + + finalwallhit=wallhit; + + bulletstrength=2; + + hitnorm=0; + + hitnorm.y=1; + + hitmove=0; + + hitrotation=0; + + } + + if(m==0){ + + if(j==0&&slomo==2){ + + soundscalefactor=soundscalefactordefault; + + if(musictoggle) + { + + /* + ALuint music = SoundFX::inst()->getMusicSource(); + alSourceStop(music); + alSourcef(music, AL_MIN_GAIN, 0); + alSourcef(music, AL_MAX_GAIN, 0); + */ + + if(person[0].whichgun==knife)whichsong=knifesong; + if(person[0].whichgun!=knife)whichsong=shootsong; + if(type==zombie_type)whichsong=zombiesong; + + ALuint music = SoundFX::inst()->getMusicSource(gSampleSet[whichsong]); + + //alSourcei(gSourceID[src_songslot], AL_BUFFER, gSampleSet[whichsong]); + alSourcef(music, AL_PITCH, 1); + alSourcePlay(music); + alSourcef(music, AL_MIN_GAIN, 1); + alSourcef(music, AL_MAX_GAIN, 1); + } + + slomo=0; + + if(whichhit==-1) + alSourcePlay(SoundFX::inst()->getFreeSource(gSampleSet[disguisekillsound], 1)); + //alSourcePlay(gSourceID[src_disguisekillsound]); + + flashamount=.5; + + flashr=1;flashg=1;flashb=1; + + } + + } + + //Impact + + oldend=end; + + //with person + + if(whichhit!=-1&&whichhit!=firstpass){ + + if(j==0)person[whichhit].dead=1; + + if(whichhit==1){ + + murderer=j; + + } + + if(person[whichhit].health==100&&j==0){ + + if(person[whichhit].type==civiliantype)civkills++; + + if(person[whichhit].type==eviltype)goodkills++; + + } + + if(person[whichhit].health==100&&j!=0){ + + badkills++; + + } + + //penetrate + + penetrate=abs(Random()%2)==1; + + if(numshots>1)penetrate=0; + + if(penetrate){bulletstrength=2; + + firstpass=whichhit; + + end=start+aim*1000;} + + if(person[j].whichgun==assaultrifle)person[whichhit].health-=20; + + if(person[j].whichgun==assaultrifle&&person[whichhit].type==zombietype)person[whichhit].health-=60; + + if(person[j].whichgun==handgun1){ + + if(person[whichhit].type!=zombietype)person[whichhit].health-=100; + + if(person[whichhit].type==zombietype)person[whichhit].health-=100; + + person[whichhit].DoAnimations(whichhit); + + } + + if(person[j].whichgun==handgun2)person[whichhit].health-=20; + + if(person[j].whichgun==handgun2&&person[whichhit].type==zombietype)person[whichhit].health-=60; + + if(person[j].whichgun==sniperrifle&&m!=0)person[whichhit].health-=30; + + if(person[j].whichgun==shotgun)person[whichhit].health-=60; + + if(person[j].whichgun==sniperrifle&&m==0){ + + if(person[whichhit].type!=zombietype)person[whichhit].health-=100; + + if(person[whichhit].type==zombietype)person[whichhit].health-=120; + + person[whichhit].DoAnimations(whichhit); + + } + + if(hitstruct.joint1->modelnum==headmodel&&person[whichhit].type!=zombietype){ + + person[whichhit].health-=60; + + } + + if(person[whichhit].type==zombietype)person[whichhit].speedmult-=.05; + + if(person[whichhit].type==zombietype)person[whichhit].maxhealth-=10; + + /* + if(whichhit==0){ + + bulletstrength=1; + + person[0].health=100; + + flashr=0; + + flashg=0; + + flashb=0; + + flashamount=1; + + float gLoc[3]; + + gLoc[0]=hitstruct.hitlocation.x/soundscalefactor; + gLoc[1]=hitstruct.hitlocation.y/soundscalefactor; + gLoc[2]=hitstruct.hitlocation.z/soundscalefactor; + + SoundFX::inst()->playFX(gSampleSet[bodywhacksound], gLoc, 1.0); + //alSourcei(gSourceID[src_bodywhacksound], AL_BUFFER, gSampleSet[bodywhacksound]); + }*/ + + person[whichhit].longdead=1; + + if(person[whichhit].health<=0){ + + person[whichhit].skeleton.offsetted=0; + + if(person[whichhit].skeleton.free!=1){ + + person[whichhit].skeleton.free=1; + + totalarea=0; + + for(int j=0;j0){ + + if(person[whichhit].killtargetvisible==0 && person[whichhit].type!=zombietype && person[whichhit].currentanimation!=getupfrontanim && person[whichhit].currentanimation!=getupbackanim){ + + if(hitstruct.joint1->modelnum==headmodel)person[whichhit].targetanimation=headpainanim; + + if(hitstruct.joint1->modelnum==chestmodel)person[whichhit].targetanimation=chestpainanim; + + if(hitstruct.joint1->modelnum==abdomenmodel)person[whichhit].targetanimation=stomachpainanim; + + if(hitstruct.joint1->label==rightelbow||hitstruct.joint1->label==rightshoulder||hitstruct.joint1->label==rightwrist||hitstruct.joint1->label==righthand)person[whichhit].targetanimation=rightarmpainanim; + + if(hitstruct.joint1->label==leftelbow||hitstruct.joint1->label==leftshoulder||hitstruct.joint1->label==leftwrist||hitstruct.joint1->label==lefthand)person[whichhit].targetanimation=leftarmpainanim; + + if(hitstruct.joint1->label==rightknee||hitstruct.joint1->label==righthip||hitstruct.joint1->label==rightankle||hitstruct.joint1->label==rightfoot)person[whichhit].targetanimation=rightlegpainanim; + + if(hitstruct.joint1->label==leftknee||hitstruct.joint1->label==lefthip||hitstruct.joint1->label==leftankle||hitstruct.joint1->label==leftfoot)person[whichhit].targetanimation=leftlegpainanim; + + person[whichhit].targetframe=0; + + person[whichhit].target=0; + + } + + person[whichhit].skeleton.offsetted=1; + + for(int j=0;j36){ + + Normalise(&person[whichhit].skeleton.joints[j].offset); + + person[whichhit].skeleton.joints[j].offset*=6; + + } + + } + + } + + if(hitstruct.joint1->modelnum==headmodel&&person[whichhit].health<=0){ + + for(int j=0;jmodelnum==headmodel){ + + if(person[j].whichgun==sniperrifle)sprites.MakeSprite(bloodspritenoup, 1, 1, 0, 0, hitstruct.hitlocation, velocity*0, 5); + + if(person[j].whichgun==sniperrifle&&penetrate)sprites.MakeSprite(bloodspritenoup, 1, 1, 0, 0, hitstruct.hitlocation, velocity*-3, 7); + + if(person[j].whichgun==shotgun)sprites.MakeSprite(bloodspritenoup, 1, 1, 0, 0, hitstruct.hitlocation, velocity*0, 5); + + if(person[j].whichgun==shotgun&&penetrate)sprites.MakeSprite(bloodspritenoup, 1, 1, 0, 0, hitstruct.hitlocation, velocity*-3, 7); + + if(person[j].whichgun==assaultrifle)sprites.MakeSprite(bloodspritenoup, 1, 1, 0, 0, hitstruct.hitlocation, velocity*0, 3); + + if(person[j].whichgun==assaultrifle&&penetrate)sprites.MakeSprite(bloodspritenoup, 1, 1, 0, 0, hitstruct.hitlocation, velocity*-3, 7); + + if(person[j].whichgun==handgun1)sprites.MakeSprite(bloodspritenoup, 1, 1, 0, 0, hitstruct.hitlocation, velocity*0, 3); + + if(person[j].whichgun==handgun1&&penetrate)sprites.MakeSprite(bloodspritenoup, 1, 1, 0, 0, hitstruct.hitlocation, velocity*-3, 4); + + if(person[j].whichgun==handgun2)sprites.MakeSprite(bloodspritenoup, 1, 1, 0, 0, hitstruct.hitlocation, velocity*0, 3); + + if(person[j].whichgun==handgun2&&penetrate)sprites.MakeSprite(bloodspritenoup, 1, 1, 0, 0, hitstruct.hitlocation, velocity*-3, 4); + + }else{ + + sprites.MakeSprite(bloodspritenoup, 1, 1, .2, .2, hitstruct.hitlocation, velocity*0, 6); + + sprites.MakeSprite(bloodspritenoup, 1, 1, .5, .5, hitstruct.hitlocation, velocity*-2, 7); + + sprites.MakeSprite(bloodspritenoup, 1, 1, .2, .2, hitstruct.hitlocation, velocity*-3, 10); + + } + + + + person[whichhit].bjoint1=hitstruct.joint1; + + person[whichhit].bjoint2=hitstruct.joint2; + + person[whichhit].bleeding=1; + + person[whichhit].bleeddelay=1; + + float gLoc[3]; + + gLoc[0]=(camera.position.x+(hitstruct.hitlocation.x-camera.position.x)/4)/soundscalefactor; + + gLoc[1]=(camera.position.y+(hitstruct.hitlocation.y-camera.position.y)/4)/soundscalefactor; + + gLoc[2]=(camera.position.z+(hitstruct.hitlocation.z-camera.position.z)/4)/soundscalefactor; + + if(!hitstruct.joint1->modelnum==headmodel){ + + if(!thirdperson)//alSourcef(gSourceID[src_bodyhitsound], AL_MIN_GAIN, 1); + SoundFX::inst()->playFX(gSampleSet[bodyhitsound], gLoc, 1.0, 1.0f, true); + + if(thirdperson)//alSourcef(gSourceID[src_bodyhitsound], AL_MIN_GAIN, .1); + SoundFX::inst()->playFX(gSampleSet[bodyhitsound], gLoc, 0.1, 1.0f, true); + + //alSourcei(gSourceID[src_bodyhitsound], AL_BUFFER, gSampleSet[bodyhitsound]); + //alSourcefv(gSourceID[src_bodyhitsound], AL_POSITION, gLoc); + + //alSourcePlay(gSourceID[src_bodyhitsound]); + + } + + if(hitstruct.joint1->modelnum==headmodel){ + + if(!thirdperson)//alSourcef(gSourceID[src_headshotsound], AL_MIN_GAIN, 1); + SoundFX::inst()->playFX(gSampleSet[headshotsound], gLoc, 1.0); + + if(thirdperson)//alSourcef(gSourceID[src_headshotsound], AL_MIN_GAIN, .1); + SoundFX::inst()->playFX(gSampleSet[headshotsound], gLoc, 0.1); + + //alSourcei(gSourceID[src_headshotsound], AL_BUFFER, gSampleSet[headshotsound]); + //alSourcefv(gSourceID[src_headshotsound], AL_POSITION, gLoc); + + //alSourcePlay(gSourceID[src_headshotsound]); + + } + + }//with wall + + if(oldend==finalwallhit){ + + decals.MakeDecal(bullethole, finalwallhit,.7,hitnorm, hitpoly, model, hitmove, hitrotation); + + XYZ velocity; + + velocity=aim*-4; + + velocity=hitnorm*3; + + if(person[j].whichgun==sniperrifle){ + + sprites.MakeSprite(smokesprite, .4, 1, 1, 1, finalwallhit, velocity, 10); + + sprites.MakeSprite(muzzleflashsprite, 1, 1, 1, 1, finalwallhit, velocity, 2); + + } + + if(person[j].whichgun==shotgun){ + + sprites.MakeSprite(smokesprite, .4, 1, 1, 1, finalwallhit, velocity, 5); + + sprites.MakeSprite(muzzleflashsprite, 1, 1, 1, 1, finalwallhit, velocity, .8); + + } + + if(person[j].whichgun==assaultrifle){ + + sprites.MakeSprite(smokesprite, .4, 1, 1, 1, finalwallhit, velocity, 6); + + sprites.MakeSprite(muzzleflashsprite, 1, 1, 1, 1, finalwallhit, velocity, 1); + + } + + if(person[j].whichgun==handgun1){ + + sprites.MakeSprite(smokesprite, .4, 1, 1, 1, finalwallhit, velocity, 6); + + sprites.MakeSprite(muzzleflashsprite, 1, 1, 1, 1, finalwallhit, velocity, 1); + + } + + if(person[j].whichgun==handgun2){ + + sprites.MakeSprite(smokesprite, .4, 1, 1, 1, finalwallhit, velocity, 6); + + sprites.MakeSprite(muzzleflashsprite, 1, 1, 1, 1, finalwallhit, velocity, 1); + + } + + float gLoc[3]; + + gLoc[0]=finalwallhit.x/soundscalefactor; + gLoc[1]=finalwallhit.y/soundscalefactor; + gLoc[2]=finalwallhit.z/soundscalefactor; + + + SoundFX::inst()->playFX(gSampleSet[wallhitsound], gLoc, 0.0, 0.6, true); + + //alSourcei(gSourceID[src_wallhitsound], AL_BUFFER, gSampleSet[wallhitsound]); + //alSourcefv(gSourceID[src_wallhitsound], AL_POSITION, gLoc); + //alSourcePlay(gSourceID[src_wallhitsound]); + + } + + lastshot[0]=start; + + lastshot[1]=oldend; + + velocity=aim*8; + + if(person[j].whichgun!=sniperrifle&&person[j].whichgun!=shotgun&&p==numshots-1)sprites.MakeSprite(smokesprite, .3, 1, 1, 1, start+aim*1.5, velocity, 3); + + if(person[j].whichgun==shotgun&&p==numshots-1)sprites.MakeSprite(smokesprite, .4, 1, 1, 1, start+aim*1.5, velocity, 5); + + if(person[j].whichgun==sniperrifle&&!zoom)sprites.MakeSprite(smokesprite, .3, 1, 1, 1, start+aim*2.2, velocity, 4); + + if(j!=0||zoom==0)sprites.MakeSprite(bullet, .07, 1, 1, .7, lastshot[0]+aim*1, lastshot[1], .2); + + //Nearby bullet whoosh + + long dot_ta,dot_tb; + + XYZ *a,*b,*c,nearest; + + a=&lastshot[0]; + + *a+=aim*1; + + b=&lastshot[1]; + + c=&camera.position; + + nearest=0; + + dot_ta = (c->x - a->x)*(b->x - a->x) + (c->y - a->y)*(b->y - a->y) + (c->z - a->z)*(b->z - a->z); + + dot_tb = (c->x - b->x)*(a->x - b->x) + (c->y - b->y)*(a->y - b->y) + (c->z - b->z)*(a->z - b->z); + + if (dot_ta <= 0 && dot_tb <= 0){ + + + + nearest.x = a->x + ((b->x - a->x) * dot_ta)/(dot_ta + dot_tb); + + nearest.y = a->y + ((b->y - a->y) * dot_ta)/(dot_ta +dot_tb); + + nearest.z = a->z + ((b->z - a->z) * dot_ta)/(dot_ta +dot_tb); + + } + + + + if(nearest.x){ + + if(findDistancefast(nearest,camera.position)<10&&(thirdperson==2||j!=0)){ + + float gLoc[3]; + + + + gLoc[0]=(camera.position.x+(nearest.x-camera.position.x))/soundscalefactor; + gLoc[1]=(camera.position.y+(nearest.y-camera.position.y))/soundscalefactor; + gLoc[2]=(camera.position.z+(nearest.z-camera.position.z))/soundscalefactor; + + SoundFX::inst()->playFX(gSampleSet[nearbulletsound], gLoc); + /* + alSourcei(gSourceID[src_nearbulletsound], AL_BUFFER, gSampleSet[nearbulletsound]); + alSourcefv(gSourceID[src_nearbulletsound], AL_POSITION, gLoc); + alSourcePlay(gSourceID[src_nearbulletsound]); + */ + + } + + } + + } + + } + + } + + } + + } + + } + + } + + + + if(!Button())oldbutton=0; + + + + if(lasersight&&person[0].whichgun!=grenade){ + + for(int j=0;j=1){ + + //Firing + + XYZ end, aim; +// XYZ oldend; + + HitStruct hitstruct,temphitstruct; + + float olddistance; + + float distance; + + int whichhit=-1; + + if(!zoom||j!=0){ + + if(person[j].whichgun==assaultrifle)aim=DoRotation(person[j].skeleton.joints[(person[j].skeleton.jointlabels[lefthand])].position-person[j].skeleton.joints[(person[j].skeleton.jointlabels[righthand])].position,0,person[j].playerrotation-2.5,0); + + if(person[j].whichgun==sniperrifle)aim=DoRotation(person[j].skeleton.joints[(person[j].skeleton.jointlabels[lefthand])].position-person[j].skeleton.joints[(person[j].skeleton.jointlabels[righthand])].position,0,person[j].playerrotation+4,0); + + if(person[j].whichgun==shotgun)aim=DoRotation(person[j].skeleton.joints[(person[j].skeleton.jointlabels[lefthand])].position-person[j].skeleton.joints[(person[j].skeleton.jointlabels[righthand])].position,0,person[j].playerrotation+4,0); + + if(person[j].whichgun==handgun1&&!thirdperson&&j==0)aim=DoRotation(person[j].skeleton.joints[(person[j].skeleton.jointlabels[righthand])].position-(person[j].skeleton.joints[person[j].skeleton.jointlabels[head]].position*.65+person[j].skeleton.joints[person[j].skeleton.jointlabels[neck]].position*.35),0,person[j].playerrotation-.9,0); + + if(person[j].whichgun==handgun1&&(thirdperson||j!=0))aim=DoRotation(person[j].skeleton.joints[(person[j].skeleton.jointlabels[righthand])].position-(person[j].skeleton.joints[person[j].skeleton.jointlabels[head]].position*.35+person[j].skeleton.joints[person[j].skeleton.jointlabels[neck]].position*.65),0,person[j].playerrotation-.9,0); + + if(person[j].whichgun==handgun2&&!thirdperson&&j==0)aim=DoRotation(person[j].skeleton.joints[(person[j].skeleton.jointlabels[righthand])].position-(person[j].skeleton.joints[person[j].skeleton.jointlabels[head]].position*.65+person[j].skeleton.joints[person[j].skeleton.jointlabels[neck]].position*.35),0,person[j].playerrotation-.9,0); + + if(person[j].whichgun==handgun2&&(thirdperson||j!=0))aim=DoRotation(person[j].skeleton.joints[(person[j].skeleton.jointlabels[righthand])].position-(person[j].skeleton.joints[person[j].skeleton.jointlabels[head]].position*.35+person[j].skeleton.joints[person[j].skeleton.jointlabels[neck]].position*.65),0,person[j].playerrotation-.9,0); + + } + + if(zoom&&j==0){ + + start=camera.position; + + aim=facing; + + } + + Normalise(&aim); + + if(person[j].whichgun==sniperrifle){ + + start=person[j].playercoords+DoRotation(person[j].skeleton.joints[(person[j].skeleton.jointlabels[lefthand])].position,0,person[j].playerrotation,0); + + start-=DoRotation(DoRotation(DoRotation(aim,0,-person[j].playerrotation,0),90,0,0),0,person[j].playerrotation,0)*(0-.4); + + } + + if(person[j].whichgun==shotgun){ + + start=person[j].playercoords+DoRotation(person[j].skeleton.joints[(person[j].skeleton.jointlabels[lefthand])].position,0,person[j].playerrotation,0); + + start-=DoRotation(DoRotation(DoRotation(aim,0,-person[j].playerrotation,0),90,0,0),0,person[j].playerrotation,0)*(0-.4); + + } + + if(person[j].whichgun==handgun1){ + + start=person[j].playercoords+DoRotation(person[j].skeleton.joints[(person[j].skeleton.jointlabels[rightwrist])].position,0,person[j].playerrotation,0); + + start-=DoRotation(DoRotation(DoRotation(aim,0,-person[j].playerrotation,0),90,0,0),0,person[j].playerrotation,0)*(.55-.4); + + } + + if(person[j].whichgun==handgun2){ + + start=person[j].playercoords+DoRotation(person[j].skeleton.joints[(person[j].skeleton.jointlabels[rightwrist])].position,0,person[j].playerrotation,0); + + start-=DoRotation(DoRotation(DoRotation(aim,0,-person[j].playerrotation,0),90,0,0),0,person[j].playerrotation,0)*(.55-.4); + + } + + if(person[j].whichgun==assaultrifle){ + + start=person[j].playercoords+DoRotation(person[j].skeleton.joints[(person[j].skeleton.jointlabels[lefthand])].position,0,person[j].playerrotation,0); + + start-=DoRotation(DoRotation(DoRotation(aim,0,-person[j].playerrotation,0),90,0,0),0,person[j].playerrotation,0)*(.25-.4); + + } + + end=start+aim*1000; + + //Blocks + + wallhit=0; + + beginx=(person[j].playercoords.x+block_spacing/2)/block_spacing-2; + + if(beginx<0)beginx=0; + + beginz=(person[j].playercoords.z+block_spacing/2)/block_spacing-2; + + if(beginz<0)beginz=0; + + + + endx=(person[j].playercoords.x+block_spacing/2)/block_spacing+2; + + if(endx>num_blocks-1)endx=num_blocks-1; + + endz=(person[j].playercoords.z+block_spacing/2)/block_spacing+2; + + if(endz>num_blocks-1)endz=num_blocks-1; + + + + if(beginx0){ + + wherex=(sprites.location[i].x+block_spacing/2)/block_spacing; + + wherey=(sprites.location[i].z+block_spacing/2)/block_spacing; + + move=0; + + move.x=wherex*block_spacing; + + move.z=wherey*block_spacing; + + whichtri=blocks[citytype[wherex][wherey]].LineCheck2(sprites.oldlocation[i],sprites.location[i],&wallhit,move,cityrotation[wherex][wherey]*90); + + if(whichtri!=-1){ + + impact=1; + + normalrotated=DoRotation(blocks[citytype[wherex][wherey]].normals[whichtri],0,cityrotation[wherex][wherey]*90,0); + + if(sprites.size[i]>1)decals.MakeDecal(crater, wallhit,9,normalrotated, whichtri, &blocks[citytype[wherex][wherey]], move, cityrotation[wherex][wherey]*90); + + sprites.location[i]=wallhit+normalrotated*.02; + + ReflectVector(&sprites.velocity[i],&normalrotated); + + sprites.velocity[i]*=.3; + + if(sprites.type[i]==grenadesprite){ + + float gLoc[3]; + + gLoc[0]=(((sprites.location[i].x)-camera.position.x)/findLengthfast(sprites.velocity[i])*5+camera.position.x)/soundscalefactor; + gLoc[1]=(((sprites.location[i].y)-camera.position.y)/findLengthfast(sprites.velocity[i])*5+camera.position.y)/soundscalefactor; + gLoc[2]=(((sprites.location[i].z)-camera.position.z)/findLengthfast(sprites.velocity[i])*5+camera.position.z)/soundscalefactor; + + whichsound=abs(Random()%2); + + + +// alSourcei(gSourceID[src_bouncesound], AL_BUFFER, gSampleSet[bouncesound+whichsound]); +// alSourcefv(gSourceID[src_bouncesound], AL_POSITION, gLoc); + if(sprites.size[i]<=1)//alSourcePlay(gSourceID[src_bouncesound+whichsound]); + SoundFX::inst()->playFX(gSampleSet[bouncesound + whichsound], gLoc); + + } + + if(findLengthfast(sprites.velocity[i])<=10)sprites.velocity[i]=0; + + } + + if(sprites.location[i].y<0){ + + impact=1; + + sprites.velocity[i].y*=-1; + + sprites.velocity[i]*=.3; + + sprites.location[i].y=0; + + if(sprites.type[i]==grenadesprite){ + + if(sprites.size[i]>1){ + + move=0; + + sprites.location[i].y=-.5; + + XYZ normish; + + normish=0; + + normish.y=1; + + decals.MakeDecal(crater, sprites.location[i],9,normish, 0, &blocks[citytype[wherex][wherey]], move, 0); + + } + + float gLoc[3]; + + gLoc[0]=(((sprites.location[i].x)-camera.position.x)/findLengthfast(sprites.velocity[i])*5+camera.position.x)/soundscalefactor; + + gLoc[1]=(((sprites.location[i].y)-camera.position.y)/findLengthfast(sprites.velocity[i])*5+camera.position.y)/soundscalefactor; + + gLoc[2]=(((sprites.location[i].z)-camera.position.z)/findLengthfast(sprites.velocity[i])*5+camera.position.z)/soundscalefactor; + + whichsound=abs(Random()%2); + + + /* + alSourcei(gSourceID[src_bouncesound], AL_BUFFER, gSampleSet[bouncesound+whichsound]); + alSourcefv(gSourceID[src_bouncesound], AL_POSITION, gLoc); + */ + if(sprites.size[i]<=1)//alSourcePlay(gSourceID[src_bouncesound+whichsound]); + SoundFX::inst()->playFX(gSampleSet[bouncesound + whichsound], gLoc); + + } + + if(findLengthfast(sprites.velocity[i])<=10)sprites.velocity[i]=0; + + } + + if(sprites.type[i]==grenadesprite&&findLengthfast(sprites.velocity[i])>20){ + + HitStruct hitstruct; + + for(int j=0;jlabel==head||hitstruct.joint2->label==head)&&person[j].type!=zombietype){ + + //alSourcei(gSourceID[src_headwhacksound], AL_BUFFER, gSampleSet[headwhacksound]); + //alSourcefv(gSourceID[src_headwhacksound], AL_POSITION, gLoc); + + if(sprites.size[i]<=1)//alSourcePlay(gSourceID[src_headwhacksound]); + SoundFX::inst()->playFX(gSampleSet[headwhacksound], gLoc); + + person[j].skeleton.free=1; + + person[j].longdead=1; + + for(int k=0;kvelocity+=sprites.velocity[i]; + + hitstruct.joint2->velocity+=sprites.velocity[i]; + + if(person[j].type==civiliantype)civkills++; + + if(person[j].type==eviltype)goodkills++; + + }else{ + + float totalarea; + + //alSourcei(gSourceID[src_bodywhacksound], AL_BUFFER, gSampleSet[bodywhacksound]); + //alSourcefv(gSourceID[src_bodywhacksound], AL_POSITION, gLoc); + + if(sprites.size[i]<=1)//alSourcePlay(gSourceID[src_bodywhacksound]); + SoundFX::inst()->playFX(gSampleSet[bodywhacksound], gLoc); + + person[j].skeleton.offsetted=1; + + for(int k=0;k9){ + + Normalise(&person[j].skeleton.joints[k].offset); + + person[j].skeleton.joints[k].offset*=3; + + } + + } + + }} + + sprites.velocity[i]*=-.3; + + } + + } + + } + + } + + sprites.oldlocation[i]=sprites.location[i]; + + } + + //Explode + + if(sprites.type[i]==grenadesprite){ + + sprites.brightness[i]-=multiplier*.3; + + if(sprites.brightness[i]<=0||(impact&&sprites.size[i]>1)){ + + sprites.brightness[i]=0; + + sprites.MakeSprite(smokesprite, 1, 1, 1, 1, sprites.location[i], facing*0, 60); + + sprites.MakeSprite(muzzleflashsprite, 1, 1, 1, 1, sprites.location[i], facing*0, 9); + + float gLoc[3]; + + gLoc[0]=(((sprites.location[i].x)-camera.position.x)/3+camera.position.x)/soundscalefactor; + + gLoc[1]=(((sprites.location[i].y)-camera.position.y)/3+camera.position.y)/soundscalefactor; + + gLoc[2]=(((sprites.location[i].z)-camera.position.z)/3+camera.position.z)/soundscalefactor; + + + /* + alSourcei(gSourceID[src_explosionsound], AL_BUFFER, gSampleSet[explosionsound]); + alSourcefv(gSourceID[src_explosionsound], AL_POSITION, gLoc); + alSourcePlay(gSourceID[src_explosionsound]); + */ + SoundFX::inst()->playFX(gSampleSet[explosionsound], gLoc); + + XYZ relation; + + camerashake=1-findDistance(person[0].playercoords,sprites.location[i])/200; + + //if(!sprites.size[i]>1){ + + overpoint=sprites.location[i]; + + overpoint.y+=3000; + + underpoint=sprites.location[i]; + + underpoint.y-=3000; + + move=0; + + wherex=(sprites.location[i].x+block_spacing/2)/block_spacing; + + wherey=(sprites.location[i].z+block_spacing/2)/block_spacing; + + move.x=wherex*block_spacing; + + move.z=wherey*block_spacing; + + XYZ temp; + + whichtri=sidewalkcollide.LineCheck2(overpoint,underpoint,&temp,move,cityrotation[wherex][wherey]*90); + + XYZ normish; + + normish=0; + + normish.y=1; + + if(whichtri>=0){ + + decals.MakeDecal(crater, sprites.location[i],9,normish, 0, &sidewalkcollide, move, cityrotation[wherex][wherey]*90); + + } + + if(whichtri==-1){ + + temp=sprites.location[i]; + + temp.y=-.5; + + move=0; + + decals.MakeDecal(crater, sprites.location[i],9,normish, 0, &sidewalkcollide, move, 0); + + } + + //} + + for(int k=0;k=1)){ + + if(person[k].skeleton.free!=1){ + + if(person[k].type==civiliantype)civkills++; + + if(person[k].type==eviltype)goodkills++; + + person[k].skeleton.free=1; + + person[k].killtargetvisible=0; + + if((findDistancefast(person[k].playercoords,sprites.location[i])<600&&person[k].skeleton.free<1)||(findDistancefast(person[k].averageloc,sprites.location[i])<600&&person[k].skeleton.free>=1)||person[k].type==playertype){ + + person[k].health-=100; + + person[k].bleeding=1; + + } + + person[k].DoAnimations(k); + + person[k].longdead=1; + + + + person[k].bleeddelay=1; + + person[k].bjoint1=&person[k].skeleton.joints[person[k].skeleton.jointlabels[head]]; + + person[k].bjoint2=&person[k].skeleton.joints[person[k].skeleton.jointlabels[neck]]; + + + + + + for(int j=0;j1)person[k].skeleton.joints[j].velocity+=relation/findDistance(person[k].skeleton.joints[j].position,sprites.location[i])*300; + + else person[k].skeleton.joints[j].velocity+=relation*300; + + } + + person[k].longdead=1; + + for(j=0;j1500&&person[k].skeleton.joints[j].existing==1&&abs(Random()%3)!=1){ + + sprites.MakeSprite(bloodspritedown, .8, 1, .2, .2,person[k].skeleton.joints[j].position, person[k].skeleton.joints[j].velocity/3, 9); + + person[k].skeleton.DeleteJoint(j); + + person[k].skeleton.broken=2; + + person[k].health=-10000; + + person[k].skeleton.joints[j].existing=0; + + } + + } + + } + + } + + } + + + + } + + } + + } + + } + + + + //camera shake + + camerashake-=multiplier; + + if(camerashake<0)camerashake=0; + + + + //camera position + + XYZ average; + + if(!zoom)average=person[0].skeleton.joints[(person[0].skeleton.jointlabels[head])].position*(person[0].aimamount/2+.5)+person[0].skeleton.joints[(person[0].skeleton.jointlabels[neck])].position*((1-person[0].aimamount)/2); + + if(zoom)average=person[0].skeleton.joints[(person[0].skeleton.jointlabels[righthand])].position; + + + + if(person[0].skeleton.free==0&&thirdperson!=2)camera.position=person[0].playercoords+DoRotation(average,0,person[0].playerrotation,0); + + if(person[0].skeleton.free==1&&thirdperson!=2)camera.position=average; + + + + //Restraints + + if(camera.position.y<.1)camera.position.y=.1; + + + + if(thirdperson!=2){ + + oldrot=camera.visrotation; + + oldrot2=camera.visrotation2; + + } + + + + //Kill count + + for(i=0;i0&&person[i].health<=0){ + + if(i==1)//alSourcePlay(gSourceID[src_losesound]); + { + float gLoc[3]; + getAuralCameraPosition(gLoc); + SoundFX::inst()->playFX(gSampleSet[losesound], gLoc, 1.0f); + } + + + if(person[i].type==civiliantype) + { + //alSourcePlay(gSourceID[src_disguisekillsound]); + float gLoc[3]; + getAuralCameraPosition(gLoc); + SoundFX::inst()->playFX(gSampleSet[disguisekillsound], gLoc, 1.0f); + + score-=300; + + } + + if(person[i].type==eviltype) + { + //alSourcePlay(gSourceID[src_soulinsound]); + float gLoc[3]; + getAuralCameraPosition(gLoc); + SoundFX::inst()->playFX(gSampleSet[soulinsound], gLoc, 1.0f); + + score+=75; + + if(person[i].whichgun==knife)score+=50; + + } + + person[i].firstlongdead=0; + + } + + person[i].oldhealth=person[i].health; + + } + + + + if(slomo==2){ + + psychicpower-=multiplier*15; + + if(psychicpower<0){ + + soundscalefactor=soundscalefactordefault; + + if(musictoggle) + { + + //alSourceStop(gSourceID[src_songslot]); + //alSourcef(gSourceID[src_songslot], AL_MIN_GAIN, 0); + //alSourcef(gSourceID[src_songslot], AL_MAX_GAIN, 0); + + if(person[0].whichgun==knife)whichsong=knifesong; + + if(person[0].whichgun!=knife)whichsong=shootsong; + + if(type==zombie_type)whichsong=zombiesong; + + ALuint music = SoundFX::inst()->getMusicSource(gSampleSet[whichsong]); + + //alSourcei(gSourceID[src_songslot], AL_BUFFER, gSampleSet[whichsong]); + alSourcef(music, AL_PITCH, 1); + alSourcePlay(music); + alSourcef(music, AL_MIN_GAIN, 1); + alSourcef(music, AL_MAX_GAIN, 1); + } + + slomo=0; + + //alSourcePlay(gSourceID[src_soulinsound]); + float gLoc[3]; + getAuralCameraPosition(gLoc); + SoundFX::inst()->playFX(gSampleSet[soulinsound], gLoc, 1.0f); + + psychicpower=0; + + flashamount=.5; + + flashr=1;flashg=1;flashb=1; + + } + + } + + psychicpower+=multiplier*5; + + if(psychicpower>10)psychicpower=10; + + + + //3d sound + + +// ALint tempInt; + + float gLoc[3]; + + gLoc[0]=camera.position.x/soundscalefactor; + + gLoc[1]=camera.position.y/soundscalefactor; + + gLoc[2]=camera.position.z/soundscalefactor; + + //Set listener position + + // hjk - put music in right spot + ALuint music = SoundFX::inst()->getMusicSource(); + alSourcefv(music, AL_POSITION, gLoc); + + // hjk - put rain in right spot + ALuint enviro = SoundFX::inst()->getEnviroSource(); + alSourcefv(enviro, AL_POSITION, gLoc); + + alListenerfv(AL_POSITION, gLoc); + + + + //Set orientation with forward and up vectors + + XYZ upvector; + + upvector=0; + + upvector.z=-1; + + + + upvector=DoRotation(upvector,-camera.rotation2+90,0,0); + + upvector=DoRotation(upvector,0,0-camera.rotation,0); + + + + float ori[6]; + + ori[0] = -facing.x; + + ori[1] = facing.y; + + ori[2] = facing.z; + + ori[3] = -upvector.x; + + ori[4] = upvector.y; + + ori[5] = upvector.z; + + alListenerfv(AL_ORIENTATION, ori); + + + + if(person[0].currentanimation==throwanim||person[0].currentanimation==diveanim||paused){ + + MoveMouse(oldmouseloc.h,oldmouseloc.v,&mouseloc); + + GetMouse(&mouseloc); + + } + + oldmouseloc=mouseloc; + + + + if(score<0)score=0; + + } + +} + + +void Game::getAuralCameraPosition(float *gLoc) +{ + gLoc[0]=camera.position.x/soundscalefactor; + gLoc[1]=camera.position.y/soundscalefactor; + gLoc[2]=camera.position.z/soundscalefactor; +} \ No newline at end of file diff --git a/blackshades_revenge/Source/Globals.cpp b/blackshades_revenge/Source/Globals.cpp new file mode 100644 index 0000000..c9559a5 --- /dev/null +++ b/blackshades_revenge/Source/Globals.cpp @@ -0,0 +1,90 @@ +#include "Quaternions.h" +#include "Constants.h" +#include "Models.h" +#include "Person.h" +#include "Game.h" + +float sinefluct; +float sinefluctprog; + +double multiplier=0; + +unsigned int gSourceID[100]; // hundred source IDs +unsigned int gSampleSet[100]; // hundred sample set ID numbers + +float precipitationhorz; +float precipitationvert; +float precipitationdensity; + +int environment; + +float soundscalefactor; +int slomo; + +Animation animation[30]; +Model skeletonmodels[10]; +Model gunmodels[11]; +Costume costume[10]; +Sprites sprites; +Decals decals; +int thirdperson; +int nocolors; +int visions; +Camera camera; +float rad2deg; +Skeleton testskeleton; + +float snowdelay; + +float camerashake; + +Fog fog; + +int forwardskey; +int backwardskey; +int leftkey; +int rightkey; +int aimkey; +int psychicaimkey; +int psychickey; + +bool blood; + +float fogcolorr; +float fogcolorg; +float fogcolorb; + +float d; +float a1,a2,a3; +float total,denom,mu; +XYZ n,pa1,pa2,pa3; + +float u0, u1, u2; +float v0, v1, v2; +float a, b; +float max; +int i, j; +bool bInter; +float pointv[3]; +float p1v[3]; +float p2v[3]; +float p3v[3]; +float normalv[3]; + +XYZ vel; +XYZ midp; +XYZ newpoint1,newpoint2; + +float oldlength; +float relaxlength; + +float friction; +int numrepeats; +float groundlevel; +float offset; +XYZ impact; +XYZ overpoint; +XYZ underpoint; +int whichtri; +XYZ normalrotated; +bool groundish; diff --git a/blackshades_revenge/Source/MacInput.cpp b/blackshades_revenge/Source/MacInput.cpp new file mode 100644 index 0000000..6d69d2c --- /dev/null +++ b/blackshades_revenge/Source/MacInput.cpp @@ -0,0 +1,65 @@ +/**> HEADER FILES <**/ +#include "MacInput.h" + +/**> Mouse Stuff <**/ +#ifdef OS9 +CursorDevicePtr theCursor; +#endif + + + +/********************> IsKeyDown() <*****/ +Boolean IsKeyDown( unsigned char *keyMap, unsigned short theKey ) +{ + long keyMapIndex; + Boolean isKeyDown; + short bitToCheck; + + // Calculate the key map index + keyMapIndex = keyMap[theKey/8]; + + // Calculate the individual bit to check + bitToCheck = theKey%8; + + // Check the status of the key + isKeyDown = ( keyMapIndex >> bitToCheck ) & 0x01; + + // Return the status of the key + return isKeyDown; + +} + +/* +#ifndef OS9 +void InitMouse() +{ + STUB_FUNCTION; +// CursorDeviceNewDevice( &theCursor ); //Mouse +} + +void MoveMouse(int xcoord, int ycoord, Point *mouseloc) +{ + STUB_FUNCTION; +// CursorDeviceNewDevice( &theCursor ); //Mouse +} + +#endif +*/ + +#ifdef OS9 +void InitMouse() +{ + CursorDeviceNewDevice( &theCursor ); //Mouse +} + +void MoveMouse(int xcoord, int ycoord, Point *mouseloc) +{ + CursorDeviceMoveTo( theCursor, xcoord, ycoord); + GetMouse(mouseloc); +} + +void DisposeMouse() +{ + CursorDeviceDisposeDevice( theCursor );//Mouse +} +#endif diff --git a/blackshades_revenge/Source/MacInput.h b/blackshades_revenge/Source/MacInput.h new file mode 100644 index 0000000..06dbef8 --- /dev/null +++ b/blackshades_revenge/Source/MacInput.h @@ -0,0 +1,112 @@ +#ifndef _MACINPUT_H_ +#define _MACINPUT_H_ + +/**> HEADER FILES <**/ +#include +#include +#ifdef OS9 +#include //Mouse +#endif + +#ifdef WIN32 +#include "Support.h" +#endif + +/**> CONSTANT DECLARATIONS <**/ +// Mac Keyboard Codes +#define MAC_1_KEY 0x12 +#define MAC_2_KEY 0x13 +#define MAC_3_KEY 0x14 +#define MAC_4_KEY 0x15 +#define MAC_5_KEY 0x17 +#define MAC_6_KEY 0x16 +#define MAC_7_KEY 0x1A +#define MAC_8_KEY 0x1C +#define MAC_9_KEY 0x19 +#define MAC_0_KEY 0x1D +#define MAC_NUMPAD_1_KEY 0x53 +#define MAC_NUMPAD_2_KEY 0x54 +#define MAC_NUMPAD_3_KEY 0x55 +#define MAC_NUMPAD_4_KEY 0x56 +#define MAC_NUMPAD_5_KEY 0x57 +#define MAC_NUMPAD_6_KEY 0x58 +#define MAC_NUMPAD_7_KEY 0x59 +#define MAC_NUMPAD_8_KEY 0x5B +#define MAC_NUMPAD_9_KEY 0x5C +#define MAC_NUMPAD_0_KEY 0x52 +#define MAC_A_KEY 0x00 +#define MAC_B_KEY 0x0B +#define MAC_C_KEY 0x08 +#define MAC_D_KEY 0x02 +#define MAC_E_KEY 0x0E +#define MAC_F_KEY 0x03 +#define MAC_G_KEY 0x05 +#define MAC_H_KEY 0x04 +#define MAC_I_KEY 0x22 +#define MAC_J_KEY 0x26 +#define MAC_K_KEY 0x28 +#define MAC_L_KEY 0x25 +#define MAC_M_KEY 0x2E +#define MAC_N_KEY 0x2D +#define MAC_O_KEY 0x1F +#define MAC_P_KEY 0x23 +#define MAC_Q_KEY 0x0C +#define MAC_R_KEY 0x0F +#define MAC_S_KEY 0x01 +#define MAC_T_KEY 0x11 +#define MAC_U_KEY 0x20 +#define MAC_V_KEY 0x09 +#define MAC_W_KEY 0x0D +#define MAC_X_KEY 0x07 +#define MAC_Y_KEY 0x10 +#define MAC_Z_KEY 0x06 +#define MAC_F1_KEY 0x7A +#define MAC_F2_KEY 0x78 +#define MAC_F3_KEY 0x63 +#define MAC_F4_KEY 0x76 +#define MAC_F5_KEY 0x60 +#define MAC_F6_KEY 0x61 +#define MAC_F7_KEY 0x62 +#define MAC_F8_KEY 0x64 +#define MAC_F9_KEY 0x65 +#define MAC_F10_KEY 0x6D +#define MAC_F11_KEY 0x67 +#define MAC_F12_KEY 0x6F +#define MAC_RETURN_KEY 0x24 +#define MAC_ENTER_KEY 0x4C +#define MAC_TAB_KEY 0x30 +#define MAC_SPACE_KEY 0x31 +#define MAC_DELETE_KEY 0x33 +#define MAC_ESCAPE_KEY 0x35 +#define MAC_COMMAND_KEY 0x37 +#define MAC_SHIFT_KEY 0x38 +#define MAC_CAPS_LOCK_KEY 0x39 +#define MAC_OPTION_KEY 0x3A +#define MAC_CONTROL_KEY 0x3B +#define MAC_PAGE_UP_KEY 0x74 +#define MAC_PAGE_DOWN_KEY 0x79 +#define MAC_INSERT_KEY 0x72 +#define MAC_DEL_KEY 0x75 +#define MAC_HOME_KEY 0x73 +#define MAC_END_KEY 0x77 +#define MAC_LEFT_BRACKET_KEY 0x21 +#define MAC_RIGHT_BRACKET_KEY 0x1E +#define MAC_ARROW_UP_KEY 0x7E +#define MAC_ARROW_DOWN_KEY 0x7D +#define MAC_ARROW_LEFT_KEY 0x7B +#define MAC_ARROW_RIGHT_KEY 0x7C + + +/**> FUNCTION PROTOTYPES <**/ +Boolean IsKeyDown( unsigned char *keyMap, unsigned short theKey ); + +void InitMouse(); +void MoveMouse(int xcoord, int ycoord, Point *mouseloc); + +//#ifdef OS9 +void RefreshMouse(Point *mouseloc); +void DisposeMouse(); +//#endif + + +#endif diff --git a/blackshades_revenge/Source/Main.cpp b/blackshades_revenge/Source/Main.cpp new file mode 100644 index 0000000..5f66769 --- /dev/null +++ b/blackshades_revenge/Source/Main.cpp @@ -0,0 +1,40 @@ +/********************> Headers <*****/ +#include "Game.h" +/********************> Globals <*****/ +Game game; +/********************> main() <*****/ + +int main( int argc, char *argv[] ) + { +#ifdef OS9 + ToolboxInit(); + if ( HasAppearance() ) + { + RegisterAppearanceClient(); + } +#endif + + + + + game.InitGL(); + game.InitGame(); + + game.EventLoop(); + + + game.Dispose(); + + +#ifdef OS9 + if ( HasAppearance() ) + { + UnregisterAppearanceClient(); + } + FlushEvents( everyEvent, 0 ); + ExitToShell(); +#endif + + return 0; +} + diff --git a/blackshades_revenge/Source/Maths.cpp b/blackshades_revenge/Source/Maths.cpp new file mode 100644 index 0000000..58e769a --- /dev/null +++ b/blackshades_revenge/Source/Maths.cpp @@ -0,0 +1,24 @@ +/**> HEADER FILES <**/ +#include "Maths.h" + +double fast_sqrt (register double arg) +{ +#ifdef OS9 + // Can replace with slower return std::sqrt(arg); + register double result; + + if (arg == 0.0) return 0.0; + + asm { + frsqrte result,arg // Calculate Square root + } + + // Newton Rhapson iterations. + result = result + 0.5 * result * (1.0 - arg * result * result); + result = result + 0.5 * result * (1.0 - arg * result * result); + + return result * arg; +#else + return sqrt(arg); +#endif +} diff --git a/blackshades_revenge/Source/Maths.h b/blackshades_revenge/Source/Maths.h new file mode 100644 index 0000000..d9a8f61 --- /dev/null +++ b/blackshades_revenge/Source/Maths.h @@ -0,0 +1,11 @@ +#ifndef _MATHS_H_ +#define _MATHS_H_ + + +/**> HEADER FILES <**/ +#include + +double fast_sqrt (register double arg); + +#endif + diff --git a/blackshades_revenge/Source/Models.cpp b/blackshades_revenge/Source/Models.cpp new file mode 100644 index 0000000..a0e69c1 --- /dev/null +++ b/blackshades_revenge/Source/Models.cpp @@ -0,0 +1,341 @@ +#include "Models.h" + +#include "Serialize.h" + +//Functions +void Model::UpdateVertexArray(){ + int i; + for(i=0;iboundingboxmax.x)boundingboxmax.x=vertex[i].x; + if(vertex[i].y>boundingboxmax.y)boundingboxmax.y=vertex[i].y; + if(vertex[i].z>boundingboxmax.z)boundingboxmax.z=vertex[i].z; + } + average=average/howmany; + boundingspherecenter=average; + boundingsphereradius=0; + for(i=0;iboundingsphereradius)boundingsphereradius=findDistancefast(average,vertex[i]); + } + boundingsphereradius=fast_sqrt(boundingsphereradius); +} + +bool Model::load(Str255 Name) +{ + FILE *tfile; + long err; + Files file; + + tfile=file.OpenFile(Name); + SetFPos(tfile,fsFromStart,0); + + // read model settings + + err=ReadShort(tfile,1,&vertexNum); + err=ReadShort(tfile,1,&TriangleNum); + + // read the model data + + err=ReadXYZ(tfile,vertexNum,vertex); + err=ReadTexturedTriangle(tfile,TriangleNum,Triangles); + + FSClose(tfile); + + UpdateVertexArray(); + + XYZ average; + int howmany; + average=0; + howmany=0; + for(int i=0;iboundingsphereradius)boundingsphereradius=findDistancefast(average,vertex[i]); + } + boundingsphereradius=fast_sqrt(boundingsphereradius); + + return 1; +} + +void Model::Scale(float xscale,float yscale,float zscale) +{ + int i; + for(i=0; ix,p1->y,p1->z, + p2->x,p2->y,p2->z, + boundingspherecenter.x,boundingspherecenter.y,boundingspherecenter.z, + boundingsphereradius)) + for (j=0;jx)*(point.x-p1->x)+(point.y-p1->y)*(point.y-p1->y)+(point.z-p1->z)*(point.z-p1->z); + if((distance Model Loading <**/ +// +// Model Maximums +// +#ifdef WIN32 +#include +#endif + +#include "Quaternions.h" +#ifdef OS9 +#include +#include +#else +#include +#include +#endif +#include "Files.h" +#include "Constants.h" + +#define max_textured_triangle 400 // maximum number of texture-filled triangles in a model +#define max_model_vertex max_textured_triangle*3 // maximum number of vertexs + + +// +// Model Structures +// + +class TexturedTriangle{ + public: + short vertex[3]; + float r,g,b; +}; + +class Model{ + public: + short vertexNum,TriangleNum; + + XYZ vertex[max_model_vertex]; + XYZ normals[max_textured_triangle]; + TexturedTriangle Triangles[max_textured_triangle]; + GLfloat vArray[max_textured_triangle*27]; + + XYZ boundingspherecenter; + float boundingsphereradius; + int LineCheck(XYZ p1,XYZ p2, XYZ *p); + int LineCheck2(XYZ p1,XYZ p2, XYZ *p,XYZ move,float rotate); + int LineCheck2(XYZ *p1,XYZ *p2, XYZ *p,XYZ *move,float *rotate); + int LineCheck3(XYZ p1,XYZ p2, XYZ *p,XYZ move,float rotate,float *d); + + void UpdateVertexArray(); + bool load(Str255 Name); + void Scale(float xscale,float yscale,float zscale); + void ScaleNormals(float xscale,float yscale,float zscale); + void Translate(float xtrans,float ytrans,float ztrans); + void CalculateNormals(); + void draw(); + void draw(float r,float g,float b); + void draw(float r,float g,float b, float o); + void draw(float r,float g,float b, float x, float y, float z); + void Rotate(float xang,float yang,float zang); + void MultColor(float howmuch); + + XYZ boundingboxmin,boundingboxmax; +}; + +#endif + diff --git a/blackshades_revenge/Source/Person.cpp b/blackshades_revenge/Source/Person.cpp new file mode 100644 index 0000000..ef7672c --- /dev/null +++ b/blackshades_revenge/Source/Person.cpp @@ -0,0 +1,1076 @@ +/**> HEADER FILES <**/ +#include "Person.h" +#include "SoundFX.h" + +extern double multiplier; +extern unsigned int gSourceID[100]; +extern unsigned int gSampleSet[100]; +extern Animation animation[30]; +extern int thirdperson; +extern int visions; +extern Camera camera; +extern float rad2deg; +extern Model gunmodels[10]; +extern Model skeletonmodels[10]; +extern Sprites sprites; +extern float soundscalefactor; +extern int slomo; + +extern int forwardskey; +extern int backwardskey; +extern int leftkey; +extern int rightkey; +extern int aimkey; +extern int psychicaimkey; +extern int psychickey; + +HitStruct Person::BulletCollideWithPlayer(int who, XYZ start, XYZ end){ + float damage=20; + XYZ tempbulletloc[2]; + XYZ collisionpoint; +// XYZ sparkpos; + GLfloat M[16]; + int collide; +// float howfar; + XYZ average; +// XYZ facing; + int howmany; + float distancemax; + HitStruct hitstruct; + hitstruct.collision=0; + //Make bounding sphere + average=0; + howmany=0; + for(int j=0;jdistancemax){ + distancemax=findDistancefast(average,skeleton.joints[j].position); + } + } + distancemax=fast_sqrt(distancemax); + //Collide with player + if(skeleton.free<1){ + start=start-playercoords; + end=end-playercoords; + if(playerrotation)start=DoRotation(start,0,-playerrotation,0); + if(playerrotation)end=DoRotation(end,0,-playerrotation,0); + } + tempbulletloc[0]=start; + tempbulletloc[1]=end; + if(sphere_line_intersection(tempbulletloc[0].x,tempbulletloc[0].y,tempbulletloc[0].z, + tempbulletloc[1].x,tempbulletloc[1].y,tempbulletloc[1].z, + average.x, average.y, average.z, distancemax)){ + for(int j=0;jposition.x)/2), + (-(skeleton.joints[j].position.y+skeleton.joints[j].parent->position.y)/2), + (-(skeleton.joints[j].position.z+skeleton.joints[j].parent->position.z)/2)); + glTranslatef(tempbulletloc[0].x,tempbulletloc[0].y,tempbulletloc[0].z); + glGetFloatv(GL_MODELVIEW_MATRIX,M); + tempbulletloc[0].x=M[12]; + tempbulletloc[0].y=M[13]; + tempbulletloc[0].z=M[14]; + glPopMatrix(); + glPushMatrix(); + glLoadIdentity(); + glScalef(1,1/skeleton.joints[j].length,1); + glRotatef(skeleton.joints[j].rotate2-90,0,0,1); + glRotatef(skeleton.joints[j].rotate1-90,0,1,0); + glTranslatef( (-(skeleton.joints[j].position.x+skeleton.joints[j].parent->position.x)/2), + (-(skeleton.joints[j].position.y+skeleton.joints[j].parent->position.y)/2), + (-(skeleton.joints[j].position.z+skeleton.joints[j].parent->position.z)/2)); + glTranslatef(tempbulletloc[1].x,tempbulletloc[1].y,tempbulletloc[1].z); + glGetFloatv(GL_MODELVIEW_MATRIX,M); + tempbulletloc[1].x=M[12]; + tempbulletloc[1].y=M[13]; + tempbulletloc[1].z=M[14]; + glPopMatrix(); + collide=skeletonmodels[skeleton.joints[j].modelnum].LineCheck(tempbulletloc[0],tempbulletloc[1],&collisionpoint); + if(collide!=-1) + { + glPushMatrix(); + glLoadIdentity(); + glTranslatef( (skeleton.joints[j].position.x+skeleton.joints[j].parent->position.x)/2, + (skeleton.joints[j].position.y+skeleton.joints[j].parent->position.y)/2, + (skeleton.joints[j].position.z+skeleton.joints[j].parent->position.z)/2); + glRotatef(-skeleton.joints[j].rotate1+90,0,1,0); + glRotatef(-skeleton.joints[j].rotate2+90,0,0,1); + glScalef(1,skeleton.joints[j].length,1); + glTranslatef(collisionpoint.x,collisionpoint.y,collisionpoint.z); + glGetFloatv(GL_MODELVIEW_MATRIX,M); + collisionpoint.x=M[12]; + collisionpoint.y=M[13]; + collisionpoint.z=M[14]; + glPopMatrix(); + hitstruct.collision=1; + hitstruct.hitlocation=collisionpoint; + hitstruct.joint1=&skeleton.joints[j]; + hitstruct.joint2=skeleton.joints[j].parent; + } + } + } + for(j=0;jposition.x+skeleton.muscles[j].parent2->position.x)/2), + (-(skeleton.muscles[j].parent1->position.y+skeleton.muscles[j].parent2->position.y)/2), + (-(skeleton.muscles[j].parent1->position.z+skeleton.muscles[j].parent2->position.z)/2)); + + glTranslatef(tempbulletloc[0].x,tempbulletloc[0].y,tempbulletloc[0].z); + glGetFloatv(GL_MODELVIEW_MATRIX,M); + tempbulletloc[0].x=M[12]; + tempbulletloc[0].y=M[13]; + tempbulletloc[0].z=M[14]; + glPopMatrix(); + glPushMatrix(); + glLoadIdentity(); + glScalef(1,1/skeleton.muscles[j].length,1); + glRotatef(skeleton.muscles[j].rotate3,0,1,0); + glRotatef(skeleton.muscles[j].rotate2-90,0,0,1); + glRotatef(skeleton.muscles[j].rotate1-90,0,1,0); + + glTranslatef( (-(skeleton.muscles[j].parent1->position.x+skeleton.muscles[j].parent2->position.x)/2), + (-(skeleton.muscles[j].parent1->position.y+skeleton.muscles[j].parent2->position.y)/2), + (-(skeleton.muscles[j].parent1->position.z+skeleton.muscles[j].parent2->position.z)/2)); + glTranslatef(tempbulletloc[1].x,tempbulletloc[1].y,tempbulletloc[1].z); + glGetFloatv(GL_MODELVIEW_MATRIX,M); + tempbulletloc[1].x=M[12]; + tempbulletloc[1].y=M[13]; + tempbulletloc[1].z=M[14]; + glPopMatrix(); + collide=skeletonmodels[skeleton.muscles[j].parent1->modelnum].LineCheck(tempbulletloc[0],tempbulletloc[1],&collisionpoint); + if(collide!=-1) + { + glPushMatrix(); + glLoadIdentity(); + glTranslatef( (skeleton.muscles[j].parent1->position.x+skeleton.muscles[j].parent2->position.x)/2, + (skeleton.muscles[j].parent1->position.y+skeleton.muscles[j].parent2->position.y)/2, + (skeleton.muscles[j].parent1->position.z+skeleton.muscles[j].parent2->position.z)/2); + glRotatef(-skeleton.muscles[j].rotate1+90,0,1,0); + glRotatef(-skeleton.muscles[j].rotate2+90,0,0,1); + glRotatef(-skeleton.muscles[j].rotate3,0,1,0); + glScalef(1,findDistance(skeleton.muscles[j].parent1->position,skeleton.muscles[j].parent2->position),1); + glTranslatef(collisionpoint.x,collisionpoint.y,collisionpoint.z); + glGetFloatv(GL_MODELVIEW_MATRIX,M); + collisionpoint.x=M[12]; + collisionpoint.y=M[13]; + collisionpoint.z=M[14]; + glPopMatrix(); + hitstruct.collision=1; + hitstruct.hitlocation=collisionpoint; + hitstruct.joint1=skeleton.muscles[j].parent1; + hitstruct.joint2=skeleton.muscles[j].parent2; + } + } + } + } + if(skeleton.free<1){ + if(playerrotation)hitstruct.hitlocation=DoRotation(hitstruct.hitlocation,0,playerrotation,0); + hitstruct.hitlocation=hitstruct.hitlocation+playercoords; + } + return hitstruct; +} + +extern float camerashake; +extern int cycle; +void Person::DoAnimations(int who){ + + if(target>1&&!skeleton.free){ + //Footstep sounds + if(who==0&&slomo==0&&(targetanimation==joganim||targetanimation==walkanim)&&(targetframe==0||targetframe==8)&&visions==0&&(onground||abs(velocity.y)<1)){ + int whichsound; + float gLoc[3]; + gLoc[0]=playercoords.x/soundscalefactor; + gLoc[1]=playercoords.y/soundscalefactor; + gLoc[2]=playercoords.z/soundscalefactor; + whichsound=footstepsound+abs(Random())%5; + + SoundFX::inst()->playFX(gSampleSet[whichsound], gLoc); + + //alSourcei(gSourceID[src_footstepsound], AL_BUFFER, gSampleSet[whichsound]); + + + //alSourcefv(gSourceID[whichsound], AL_POSITION, gLoc); + //alSourcePlay(gSourceID[whichsound]); + } + if(targetanimation==zombieeatanim&&(targetframe==3)){ +// int whichsound; + float gLoc[3]; + XYZ soundpoint=(DoRotation(skeleton.joints[skeleton.jointlabels[head]].position,0,playerrotation,0)+playercoords); + gLoc[0]=soundpoint.x/soundscalefactor; + gLoc[1]=soundpoint.y/soundscalefactor; + gLoc[2]=soundpoint.z/soundscalefactor; + + SoundFX::inst()->playFX(gSampleSet[bodyhitsound], gLoc, 0.1f, 1.0f, true); + //alSourcei(gSourceID[src_bodyhitsound], AL_BUFFER, gSampleSet[bodyhitsound]); + //alSourcefv(gSourceID[src_bodyhitsound], AL_POSITION, gLoc); + //alSourcePlay(gSourceID[src_bodyhitsound]); + + bleeding=1; + bleeddelay=1; + bjoint1=&skeleton.joints[skeleton.jointlabels[head]]; + bjoint2=&skeleton.joints[skeleton.jointlabels[neck]]; + } + targetframe=currentframe; + currentanimation=targetanimation; + if(!backwardsanim){targetframe++; + if(targetframe>animation[currentanimation].numframes-1)targetframe=0;} + if(backwardsanim){targetframe--; + if(targetframe<0)targetframe=animation[currentanimation].numframes-1;} + target=0; + if((currentanimation==getupfrontanim||currentanimation==getupbackanim)&&targetframe==0){ + targetanimation=idleanim; + } + if(targetanimation==diveanim&¤tanimation==diveanim&&targetframe==0){ + targetanimation=getupfrontanim; + float gLoc[3]; + XYZ soundpoint=(DoRotation(skeleton.joints[skeleton.jointlabels[head]].position,0,playerrotation,0)+playercoords); + gLoc[0]=soundpoint.x/soundscalefactor; + gLoc[1]=soundpoint.y/soundscalefactor; + gLoc[2]=soundpoint.z/soundscalefactor; + + SoundFX::inst()->playFX(gSampleSet[bodywhacksound], gLoc); + //alSourcei(gSourceID[src_bodywhacksound], AL_BUFFER, gSampleSet[bodywhacksound]); + //alSourcefv(gSourceID[src_bodywhacksound], AL_POSITION, gLoc); + //alSourcePlay(gSourceID[src_bodywhacksound]); + } + if(currentanimation==throwanim&&targetframe==0){ + targetanimation=idleanim; + } + if(currentanimation==thrownanim&&targetframe==0){ + skeleton.offsetted=0; + skeleton.free=1; + longdead=1; + for(int j=0;janimation[currentanimation].speed[currentframe]) + target+=multiplier*animation[targetanimation].speed[currentframe]*speed; + if(animation[targetanimation].speed[currentframe]<=animation[currentanimation].speed[currentframe]) + target+=multiplier*animation[currentanimation].speed[currentframe]*speed; + } + if(currentanimation==lyinganim){ + target+=multiplier*animation[targetanimation].speed[targetframe]*speed; + } + if(((currentanimation==crouchanim)&&(targetanimation!=crouchanim))||((currentanimation!=crouchanim)&&(targetanimation==crouchanim)))target+=multiplier*animation[crouchanim].speed[0]*2; + if(currentanimation==idleanim&&targetanimation==idleanim)target-=multiplier*animation[idleanim].speed[0]/2; + + if(target>1)currentframe=targetframe; + + for(int i=0;i0||whichgun==grenade)&&whichgun!=nogun){ + if(aiming&&targetanimation!=joganim){ + if(aimamount<1)aimamount+=multiplier*4; + if(aimamount>1)aimamount=1; + } + if(!aiming||targetanimation==joganim){ + if(aimamount>0)aimamount-=multiplier*4; + if(aimamount<0)aimamount=0; + } + if(grenphase==1){ + if(grenamount<1)grenamount+=multiplier*4; + if(grenamount>1)grenamount=1; + } + if(grenphase==0){ + if(grenamount>0)grenamount-=multiplier*4; + if(grenamount<0)grenamount=0; + } + rotatearound=skeleton.joints[skeleton.jointlabels[neck]].position; + for(int i=0;i0){ + oldpos=skeleton.joints[i].position; + skeleton.joints[i].position=animation[grenadechargeanim].position[i][0]; + if(currentanimation==crouchanim||targetanimation==crouchanim)skeleton.joints[i].position-=(animation[idleanim].position[skeleton.jointlabels[neck]][0]-skeleton.joints[skeleton.jointlabels[neck]].position); + skeleton.joints[i].position=skeleton.joints[i].position*(grenamount)+oldpos*(1-grenamount); + } + if(thirdperson||who!=0)skeleton.joints[i].position+=facingdown*.4f; + if(currentanimation!=crouchanim)skeleton.joints[i].position-=facinghalf*recoil*.35f; + if(currentanimation==crouchanim)skeleton.joints[i].position-=facinghalf*recoil*.1f; + } + } + } + //Whack + if(attackframe>-1&&whichgun!=grenade){ + for(int i=0;i0&&attackframe0)attacktarget+=multiplier*animation[riflehitanim].speed[attackframe-1]*2; + if(attacktarget>1){ + attacktarget=0; + attackframe++; + if(attackframe>animation[riflehitanim].numframes)attackframe=-1; + } + } + //Throw grenade + if(attackframe>-1&&whichgun==grenade&&ammo>0){ + for(int i=0;i0&&attackframe0)attacktarget+=multiplier*animation[grenadethrowanim].speed[attackframe-1]*2; + if(attacktarget>1){ + attacktarget=0; + attackframe++; + if(attackframe>animation[grenadethrowanim].numframes){ + attackframe=-1; + } + if(attackframe==animation[grenadethrowanim].numframes-1&&ammo>0){ + ammo=-1; + sprites.MakeSprite(grenadesprite, 1, 1, 1, 1, DoRotation(skeleton.joints[skeleton.jointlabels[righthand]].position,0,playerrotation,0)+playercoords, DoRotation(facing,0,playerrotation,0)*30+velocity, 1); + sprites.MakeSprite(spoonsprite, 1, 1, 1, 1, DoRotation(skeleton.joints[skeleton.jointlabels[righthand]].position,0,playerrotation,0)+playercoords, DoRotation(facing,0,playerrotation,0)*10+velocity, 1); + sprites.MakeSprite(pinsprite, 1, 1, 1, 1, DoRotation(skeleton.joints[skeleton.jointlabels[lefthand]].position,0,playerrotation,0)+playercoords, facing*.1f+velocity, 1); + XYZ soundsource=DoRotation(skeleton.joints[skeleton.jointlabels[righthand]].position,0,playerrotation,0)+playercoords; + float gLoc[3]; + gLoc[0]=soundsource.x/soundscalefactor; + gLoc[1]=soundsource.y/soundscalefactor; + gLoc[2]=soundsource.z/soundscalefactor; + + SoundFX::inst()->playFX(gSampleSet[grenadethrowsound], gLoc); + //alSourcei(gSourceID[src_grenadethrowsound], AL_BUFFER, gSampleSet[grenadethrowsound]); + //alSourcefv(gSourceID[src_grenadethrowsound], AL_POSITION, gLoc); + //alSourcePlay(gSourceID[src_grenadethrowsound]); + } + } + } + + rotatearound=skeleton.joints[skeleton.jointlabels[abdomen]].position; + if(who==0) + for(int i=0;i0){ + aiming=0; + reloading-=multiplier; + } + if(ammo<0&&reloads[whichgun]>0&&reloading<=0){ + if(whichgun!=grenade){ + float gLoc[3]; + //ALint tempint; + gLoc[0]=playercoords.x/soundscalefactor; + gLoc[1]=playercoords.y/soundscalefactor; + gLoc[2]=playercoords.z/soundscalefactor; + + +/* +#ifdef DEBIAN_NEEDS_TO_UPDATE_THEIR_OPENAL + alGetSourceiv(gSourceID[src_reloadsound], AL_SOURCE_STATE, &tempint); +#else + alGetSourcei(gSourceID[src_reloadsound], AL_SOURCE_STATE, &tempint); +#endif + + if (tempint != AL_PLAYING){ + alSourcei(gSourceID[src_reloadsound], AL_BUFFER, gSampleSet[reloadsound]); + alSourcefv(gSourceID[src_reloadsound], AL_POSITION, gLoc); + alSourcePlay(gSourceID[src_reloadsound]); + } + + */ + // I don't think aboveis needed... We'll see. + SoundFX::inst()->playFX(gSampleSet[reloadsound], gLoc); + } + reloading=3; + aiming=0; + if(whichgun==sniperrifle)ammo=5; + if(whichgun==assaultrifle)ammo=25; + if(whichgun==handgun1)ammo=12; + if(whichgun==handgun2)ammo=16; + if(whichgun==grenade){ammo=1; reloading=1;} + if(whichgun==shotgun)ammo=6; + reloads[whichgun]--; + } + if(reloads[whichgun]==0&&whichgun==grenade&&ammo<=0){ + whichgun=nogun; + } + if(reloading<0){ + reloading=0; + aiming=1; + } + } + } +} + +void Person::DoAnimationslite(int who){ + + int oldanimation=currentanimation; + if(target>1&&!skeleton.free){ + //Footstep sounds + if(who==0&&(targetanimation==joganim||targetanimation==walkanim)&&(targetframe==0||targetframe==8)&&visions==0&&(onground||abs(velocity.y)<1)){ + int whichsound; + float gLoc[3]; + gLoc[0]=playercoords.x/soundscalefactor; + gLoc[1]=playercoords.y/soundscalefactor; + gLoc[2]=playercoords.z/soundscalefactor; + whichsound=footstepsound+abs(Random())%5; + + SoundFX::inst()->playFX(gSampleSet[whichsound], gLoc); + //alSourcei(gSourceID[src_footstepsound], AL_BUFFER, gSampleSet[whichsound]); + //alSourcefv(gSourceID[src_footstepsound], AL_POSITION, gLoc); + //alSourcePlay(gSourceID[src_footstepsound]); + } + if(targetanimation==zombieeatanim&&(targetframe==3)){ +// int whichsound; + float gLoc[3]; + XYZ soundpoint=(DoRotation(skeleton.joints[skeleton.jointlabels[head]].position,0,playerrotation,0)+playercoords); + gLoc[0]=soundpoint.x/soundscalefactor; + gLoc[1]=soundpoint.y/soundscalefactor; + gLoc[2]=soundpoint.z/soundscalefactor; + + SoundFX::inst()->playFX(gSampleSet[bodyhitsound], gLoc, 0.1f, 1.0f, true); + //alSourcei(gSourceID[src_bodyhitsound], AL_BUFFER, gSampleSet[bodyhitsound]); + //alSourcefv(gSourceID[src_bodyhitsound], AL_POSITION, gLoc); + //alSourcePlay(gSourceID[src_bodyhitsound]); + bleeding=1; + bleeddelay=1; + bjoint1=&skeleton.joints[skeleton.jointlabels[head]]; + bjoint2=&skeleton.joints[skeleton.jointlabels[neck]]; + } + targetframe=currentframe; + currentanimation=targetanimation; + if(!backwardsanim){targetframe++; + if(targetframe>animation[currentanimation].numframes-1)targetframe=0;} + if(backwardsanim){targetframe--; + if(targetframe<0)targetframe=animation[currentanimation].numframes-1;} + target=0; + if((currentanimation==getupfrontanim||currentanimation==getupbackanim)&&targetframe==0){ + targetanimation=idleanim; + } + } + + if(!skeleton.free){ + if(currentanimation!=lyinganim){ + if(animation[targetanimation].speed[currentframe]>animation[currentanimation].speed[currentframe]) + target+=multiplier*animation[targetanimation].speed[currentframe]*speed; + if(animation[targetanimation].speed[currentframe]<=animation[currentanimation].speed[currentframe]) + target+=multiplier*animation[currentanimation].speed[currentframe]*speed; + } + if(currentanimation==lyinganim){ + target+=multiplier*animation[targetanimation].speed[targetframe]*speed; + } + if(((currentanimation==crouchanim)&&(targetanimation!=crouchanim))||((currentanimation!=crouchanim)&&(targetanimation==crouchanim)))target+=multiplier*animation[crouchanim].speed[0]*2; + if(currentanimation==idleanim&&targetanimation==idleanim)target-=multiplier*animation[idleanim].speed[0]/2; + + if(target>1)currentframe=targetframe; + } +} + +void Person::DoStuff(int who){ + int moveanim; + + if((targetanimation!=idleanim&&targetanimation!=crouchanim)||visions==1)playerlowrotation=playerrotation; + if(targetanimation!=crouchanim&¤tanimation!=crouchanim){ + if(playerrotation>playerlowrotation+50){playerlowrotation=playerrotation-50; targetanimation=walkanim; targetframe=0; target=0;} + if(playerrotationplayerlowrotation+70){playerrotation=playerlowrotation+70;} + if(playerrotationtemppoint2.x)gunrotate1=360-gunrotate1; + tempforward=target-start; + tempforward=DoRotation(tempforward,-90,0,0); + tempforward=DoRotation(tempforward,0,gunrotate1-90,0); + tempforward=DoRotation(tempforward,0,0,gunrotate2-90); + tempforward.y=0; + Normalise(&tempforward); + gunrotate3=acos(0-tempforward.z)*rad2deg; + if(0>tempforward.x)gunrotate3=360-gunrotate3; +} + +extern Model skeletonmodels[10]; +extern Costume costume[2]; +int Person::DrawSkeleton(int who){ + //GLfloat M[16]; + //Guns + if(whichgun==sniperrifle){ + FindRotationGun(skeleton.joints[skeleton.jointlabels[righthand]].position,skeleton.joints[skeleton.jointlabels[lefthand]].position); + glPushMatrix(); + glTranslatef( skeleton.joints[skeleton.jointlabels[righthand]].position.x, + skeleton.joints[skeleton.jointlabels[righthand]].position.y, + skeleton.joints[skeleton.jointlabels[righthand]].position.z); + glRotatef(-gunrotate1+90,0,1,0); + glRotatef(-gunrotate2+90,0,0,1); + glRotatef(-gunrotate3,0,1,0); + gunmodels[sniperriflemodel].draw(); + glPopMatrix(); + } + + if(whichgun==shotgun){ + FindRotationGun(skeleton.joints[skeleton.jointlabels[righthand]].position,skeleton.joints[skeleton.jointlabels[lefthand]].position); + glPushMatrix(); + glTranslatef( skeleton.joints[skeleton.jointlabels[righthand]].position.x, + skeleton.joints[skeleton.jointlabels[righthand]].position.y, + skeleton.joints[skeleton.jointlabels[righthand]].position.z); + glRotatef(2,1,0,0); + glRotatef(-gunrotate1+90+1,0,1,0); + glRotatef(-gunrotate2+90,0,0,1); + glRotatef(-gunrotate3,0,1,0); + glTranslatef(0,-.4f,0); + gunmodels[shotgunmodel].draw(); + glPopMatrix(); + } + + if(whichgun==assaultrifle){ + FindRotationGun(skeleton.joints[skeleton.jointlabels[righthand]].position,skeleton.joints[skeleton.jointlabels[lefthand]].position); + glPushMatrix(); + glTranslatef( skeleton.joints[skeleton.jointlabels[righthand]].position.x, + skeleton.joints[skeleton.jointlabels[righthand]].position.y, + skeleton.joints[skeleton.jointlabels[righthand]].position.z); + glRotatef(-gunrotate1+90,0,1,0); + glRotatef(-gunrotate2+90,0,0,1); + glRotatef(-gunrotate3,0,1,0); + gunmodels[assaultriflemodel].draw(); + glPopMatrix(); + } + + if(whichgun==handgun1){ + if(!thirdperson&&who==0)FindRotationGun(skeleton.joints[skeleton.jointlabels[righthand]].position,(skeleton.joints[skeleton.jointlabels[head]].position*.65f+skeleton.joints[skeleton.jointlabels[neck]].position*.35f)); + if(thirdperson||who!=0)FindRotationGun(skeleton.joints[skeleton.jointlabels[righthand]].position,(skeleton.joints[skeleton.jointlabels[head]].position*.35f+skeleton.joints[skeleton.jointlabels[neck]].position*.65f)); + glPushMatrix(); + glTranslatef( skeleton.joints[skeleton.jointlabels[righthand]].position.x, + skeleton.joints[skeleton.jointlabels[righthand]].position.y, + skeleton.joints[skeleton.jointlabels[righthand]].position.z); + glRotatef(-gunrotate1+90-1.5,0,1,0); + glRotatef(-gunrotate2+90,0,0,1); + glRotatef(-gunrotate3,0,1,0); + glTranslatef(0,0,.15f); + gunmodels[handgunbasemodel].draw(); + glTranslatef(0,-recoil*.3,0); + gunmodels[handgunslidemodel].draw(); + glPopMatrix(); + } + + if(whichgun==handgun2){ + if(!thirdperson&&who==0)FindRotationGun(skeleton.joints[skeleton.jointlabels[righthand]].position,(skeleton.joints[skeleton.jointlabels[head]].position*.65f+skeleton.joints[skeleton.jointlabels[neck]].position*.35f)); + if(thirdperson||who!=0)FindRotationGun(skeleton.joints[skeleton.jointlabels[righthand]].position,(skeleton.joints[skeleton.jointlabels[head]].position*.35f+skeleton.joints[skeleton.jointlabels[neck]].position*.65f)); + glPushMatrix(); + glTranslatef( skeleton.joints[skeleton.jointlabels[righthand]].position.x, + skeleton.joints[skeleton.jointlabels[righthand]].position.y, + skeleton.joints[skeleton.jointlabels[righthand]].position.z); + glRotatef(-gunrotate1+90-1.5,0,1,0); + glRotatef(-gunrotate2+90,0,0,1); + glRotatef(-gunrotate3,0,1,0); + glTranslatef(0,0,.15f); + gunmodels[handgun2basemodel].draw(); + glTranslatef(0,-recoil*.3,0); + gunmodels[handgun2slidemodel].draw(); + glPopMatrix(); + } + + if(whichgun==grenade){ + glPushMatrix(); + glTranslatef( skeleton.joints[skeleton.jointlabels[righthand]].position.x, + skeleton.joints[skeleton.jointlabels[righthand]].position.y, + skeleton.joints[skeleton.jointlabels[righthand]].position.z); + glRotatef(-90,1,0,0); + glTranslatef(0,0,.05f); + if(reloading<=0){ + gunmodels[grenadebasemodel].draw(); + if(grenphase==0)gunmodels[grenadepinmodel].draw(); + glTranslatef(0,0,.005f); + gunmodels[grenadespoonmodel].draw(); + } + glPopMatrix(); + } + + if(whichgun==grenade){ + glPushMatrix(); + glTranslatef( skeleton.joints[skeleton.jointlabels[lefthand]].position.x, + skeleton.joints[skeleton.jointlabels[lefthand]].position.y, + skeleton.joints[skeleton.jointlabels[lefthand]].position.z); + glRotatef(-90,1,0,0); + glTranslatef(0,0,-.15f); + if(reloading<=0){ + if(grenphase==1)gunmodels[grenadepinmodel].draw(); + } + glPopMatrix(); + } + if(!litup){ + glDisable(GL_LIGHT1); + } + if(litup){ + GLfloat LightAmbient[]= { 0,0,0, 1.0f}; + GLfloat LightDiffuse[]= { 1,1,1, 1.0f }; + XYZ lightpoint; + lightpoint=skeleton.joints[skeleton.jointlabels[lefthand]].position; + GLfloat LightPosition[]= {lightpoint.x,lightpoint.y,lightpoint.z,0}; + glLightfv(GL_LIGHT1, GL_POSITION, LightPosition); + glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); + glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); + glEnable(GL_LIGHT1); + + litup=0; + } + + //Find forward vectors + if(who==0||skeleton.free!=0||skeleton.offsetted!=0||whichgun!=nogun||currentanimation==lyinganim||((currentanimation==getupfrontanim||currentanimation==getupbackanim)&&targetanimation==idleanim)){ + if(!(skeleton.free==1&&longdead<=0)){ + if(skeleton.offsetted&&skeleton.free<1){ + XYZ normal; + skeleton.offsetted=0; + for(int i=0;i0&&health==100&&whichgun!=nogun){ + //Facing + XYZ facing; + XYZ facingdown; + //Facing + facing=0; + facing.z=1; + + facing=DoRotation(facing,camera.rotation2,0,0); + facingdown=DoRotation(facing,90,0,0); + skeleton.specialforward[1]=skeleton.specialforward[1]*(1-aimamount)+facingdown*aimamount; + skeleton.specialforward[2]=skeleton.specialforward[2]*(1-aimamount)+facingdown*aimamount; + } + + skeleton.specialforward[3]=skeleton.joints[skeleton.jointlabels[righthip]].position+skeleton.joints[skeleton.jointlabels[rightankle]].position; + skeleton.specialforward[3]=skeleton.specialforward[3]/2-skeleton.joints[skeleton.jointlabels[rightknee]].position; + skeleton.specialforward[3]+=skeleton.lowforward*.2f; + Normalise(&skeleton.specialforward[3]); + skeleton.specialforward[4]=skeleton.joints[skeleton.jointlabels[lefthip]].position+skeleton.joints[skeleton.jointlabels[leftankle]].position; + skeleton.specialforward[4]=skeleton.specialforward[4]/2-skeleton.joints[skeleton.jointlabels[leftknee]].position; + skeleton.specialforward[4]+=skeleton.lowforward*.2f; + Normalise(&skeleton.specialforward[4]); + + //Find joint rotations + for(int i=0;iposition.x)/2, + (skeleton.joints[i].position.y+skeleton.joints[i].parent->position.y)/2, + (skeleton.joints[i].position.z+skeleton.joints[i].parent->position.z)/2); + glRotatef(-skeleton.joints[i].rotate1+90,0,1,0); + glRotatef(-skeleton.joints[i].rotate2+90,0,0,1); + glRotatef(-skeleton.joints[i].rotate3,0,1,0); + if(skeleton.joints[i].modelnum==0&&(who!=0||thirdperson))skeletonmodels[skeleton.joints[i].modelnum].draw(costume[whichcostume].headcolor[0],costume[whichcostume].headcolor[1],costume[whichcostume].headcolor[2]); + if(skeleton.joints[i].modelnum==0&&(who==0&&thirdperson))skeletonmodels[9].draw(); + if(skeleton.joints[i].modelnum==1&&(who!=0||thirdperson))skeletonmodels[skeleton.joints[i].modelnum].draw(costume[whichcostume].chestcolor[0],costume[whichcostume].chestcolor[1],costume[whichcostume].chestcolor[2]); + if(skeleton.joints[i].modelnum==2)skeletonmodels[skeleton.joints[i].modelnum].draw(costume[whichcostume].abdomencolor[0],costume[whichcostume].abdomencolor[1],costume[whichcostume].abdomencolor[2]); + if(skeleton.joints[i].modelnum==3)skeletonmodels[skeleton.joints[i].modelnum].draw(costume[whichcostume].upperarmcolor[0],costume[whichcostume].upperarmcolor[1],costume[whichcostume].upperarmcolor[2]); + if(skeleton.joints[i].modelnum==4)skeletonmodels[skeleton.joints[i].modelnum].draw(costume[whichcostume].lowerarmcolor[0],costume[whichcostume].lowerarmcolor[1],costume[whichcostume].lowerarmcolor[2]); + if(skeleton.joints[i].modelnum==5)skeletonmodels[skeleton.joints[i].modelnum].draw(costume[whichcostume].handcolor[0],costume[whichcostume].handcolor[1],costume[whichcostume].handcolor[2]); + if(skeleton.joints[i].modelnum==6)skeletonmodels[skeleton.joints[i].modelnum].draw(costume[whichcostume].upperlegcolor[0],costume[whichcostume].upperlegcolor[1],costume[whichcostume].upperlegcolor[2]); + if(skeleton.joints[i].modelnum==7)skeletonmodels[skeleton.joints[i].modelnum].draw(costume[whichcostume].lowerlegcolor[0],costume[whichcostume].lowerlegcolor[1],costume[whichcostume].lowerlegcolor[2]); + if(skeleton.joints[i].modelnum==8)skeletonmodels[skeleton.joints[i].modelnum].draw(costume[whichcostume].footcolor[0],costume[whichcostume].footcolor[1],costume[whichcostume].footcolor[2]); + glPopMatrix(); + } + } + + for(i=0;iposition.x+skeleton.muscles[i].parent2->position.x)/2, + (skeleton.muscles[i].parent1->position.y+skeleton.muscles[i].parent2->position.y)/2, + (skeleton.muscles[i].parent1->position.z+skeleton.muscles[i].parent2->position.z)/2); + glRotatef(-skeleton.muscles[i].rotate1+90,0,1,0); + glRotatef(-skeleton.muscles[i].rotate2+90,0,0,1); + glRotatef(-skeleton.muscles[i].rotate3,0,1,0); + if(skeleton.muscles[i].parent1->modelnum==0&&(who!=0||thirdperson))skeletonmodels[skeleton.muscles[i].parent1->modelnum].draw(costume[whichcostume].headcolor[0],costume[whichcostume].headcolor[1],costume[whichcostume].headcolor[2]); + if(skeleton.muscles[i].parent1->modelnum==0&&(who==0&&thirdperson))skeletonmodels[9].draw(); + if(skeleton.muscles[i].parent1->modelnum==1&&(who!=0||thirdperson))skeletonmodels[skeleton.muscles[i].parent1->modelnum].draw(costume[whichcostume].chestcolor[0],costume[whichcostume].chestcolor[1],costume[whichcostume].chestcolor[2]); + if(skeleton.muscles[i].parent1->modelnum==2)skeletonmodels[skeleton.muscles[i].parent1->modelnum].draw(costume[whichcostume].abdomencolor[0],costume[whichcostume].abdomencolor[1],costume[whichcostume].abdomencolor[2]); + if(skeleton.muscles[i].parent1->modelnum==3)skeletonmodels[skeleton.muscles[i].parent1->modelnum].draw(costume[whichcostume].upperarmcolor[0],costume[whichcostume].upperarmcolor[1],costume[whichcostume].upperarmcolor[2]); + if(skeleton.muscles[i].parent1->modelnum==4)skeletonmodels[skeleton.muscles[i].parent1->modelnum].draw(costume[whichcostume].lowerarmcolor[0],costume[whichcostume].lowerarmcolor[1],costume[whichcostume].lowerarmcolor[2]); + if(skeleton.muscles[i].parent1->modelnum==5)skeletonmodels[skeleton.muscles[i].parent1->modelnum].draw(costume[whichcostume].handcolor[0],costume[whichcostume].handcolor[1],costume[whichcostume].handcolor[2]); + if(skeleton.muscles[i].parent1->modelnum==6)skeletonmodels[skeleton.muscles[i].parent1->modelnum].draw(costume[whichcostume].upperlegcolor[0],costume[whichcostume].upperlegcolor[1],costume[whichcostume].upperlegcolor[2]); + if(skeleton.muscles[i].parent1->modelnum==7)skeletonmodels[skeleton.muscles[i].parent1->modelnum].draw(costume[whichcostume].lowerlegcolor[0],costume[whichcostume].lowerlegcolor[1],costume[whichcostume].lowerlegcolor[2]); + if(skeleton.muscles[i].parent1->modelnum==8)skeletonmodels[skeleton.muscles[i].parent1->modelnum].draw(costume[whichcostume].footcolor[0],costume[whichcostume].footcolor[1],costume[whichcostume].footcolor[2]); + + glPopMatrix(); + } + } + if(whichgun==knife){ + glPushMatrix(); + glTranslatef( skeleton.joints[skeleton.jointlabels[righthand]].position.x, + skeleton.joints[skeleton.jointlabels[righthand]].position.y, + skeleton.joints[skeleton.jointlabels[righthand]].position.z); + glRotatef(-skeleton.joints[skeleton.jointlabels[righthand]].rotate1+90-1.5,0,1,0); + glRotatef(-skeleton.joints[skeleton.jointlabels[righthand]].rotate2+90,0,0,1); + glRotatef(-skeleton.joints[skeleton.jointlabels[righthand]].rotate3,0,1,0); + glTranslatef(0,-.2f,0); + gunmodels[knifemodel].draw(); + glPopMatrix(); + } + if(skeleton.offsetted && skeleton.free<1){ + for(int i=0;i HEADER FILES <**/ +#ifdef WIN32 +#include +#endif + +#include +#ifdef OS9 +#include +#else +#include +#endif +#ifdef OS9 +#include "alut.h" +#else + #ifdef WIN32 + #include + #include + #else + #include + #include + #endif +#endif +#include "Quaternions.h" +#include "Constants.h" +#include "Skeleton.h" +#include "Models.h" +#include "Camera.h" +#include "Sprites.h" + +#define playertype 0 +#define civiliantype 1 +#define eviltype 2 +#define viptype 3 +#define evilsnipertype 4 +#define evilassaultrifletype 5 +#define zombietype 6 + +class HitStruct +{ + public: + Joint *joint1; + Joint *joint2; + XYZ hitlocation; + bool collision; +}; + +class Person +{ + public: + int eaten; + int currentframe; + int targetframe; + int currentanimation; + int targetanimation; + float target; + float playerhealth; + int modelnum; + XYZ oldplayercoords; + XYZ playercoords; + XYZ playervelocity; + float playerrotation; + float playerrotation2; + float playerlowrotation; + float pathcheckdelay; + bool onground; + bool backwardsanim; + XYZ facing; + XYZ velocity; + float shotdelay; + bool litup; + + bool existing; + + int type; + + int whichcostume; + + Skeleton skeleton; + Animation tempanimation; + + bool freshshootkey; + bool freshkickkey; + int bufferattack; + int jump_key; + int left_key; + int right_key; + int duck_key; + int shoot_key; + int kick_key; + int block_key; + + float speed; + int aiming; + int grenphase; + float grenamount; + float aimamount; + float speedmult; + float pathsize; + + int pathnum; + int oldpathnum; + int oldoldpathnum; + int oldoldoldpathnum; + XYZ pathtarget; + int whichblockx; + int whichblocky; + + bool dead; + + XYZ averageloc; + XYZ oldaverageloc; + + float lastdistancevictim; + + bool firstlongdead; + float longdead; + + Joint *bjoint1,*bjoint2; + float bleeding; + float bleeddelay; + + float attacktarget; + int attackframe; + int killtarget; + bool killtargetvisible; + + float gunrotate1, gunrotate2, gunrotate3; + float recoil; + int whichgun; + float oldhealth; + float health; + float maxhealth; + float reloading; + int ammo; + int reloads[10]; + bool running; + bool onpath; + + void FindRotationGun(XYZ start, XYZ target); + + int DrawSkeleton(int who); + void DoStuff(int who); + void DoAnimations(int who); + void DoAnimationslite(int who); + HitStruct BulletCollideWithPlayer(int who, XYZ start, XYZ end); +}; + +class Costume +{ + public: + float headcolor[3]; + float handcolor[3]; + float footcolor[3]; + float upperarmcolor[3]; + float lowerarmcolor[3]; + float upperlegcolor[3]; + float lowerlegcolor[3]; + float abdomencolor[3]; + float chestcolor[3]; +}; + + +#endif diff --git a/blackshades_revenge/Source/PhysicsMath.h b/blackshades_revenge/Source/PhysicsMath.h new file mode 100644 index 0000000..c975941 --- /dev/null +++ b/blackshades_revenge/Source/PhysicsMath.h @@ -0,0 +1,1432 @@ +#ifndef _PHYSICSMATH_H_ + +#define _PHYSICSMATH_H_ + + + +#include + +#include "Quaternions.h" + + + +//------------------------------------------------------------------------// + +// Misc. Constants + +//------------------------------------------------------------------------// + + + +float const pi = 3.14159265f; + +float const g = -32.174f; // acceleration due to gravity, ft/s^2 + +float const rho = 0.0023769f; // desity of air at sea level, slugs/ft^3 + +float const tol = 0.0000000001f; // float type tolerance + + + + + +//------------------------------------------------------------------------// + +// Misc. Functions + +//------------------------------------------------------------------------// + +inline float DegreesToRadians(float deg); + +inline float RadiansToDegrees(float rad); + + + +inline float DegreesToRadians(float deg) + +{ + + return deg * pi / 180.0f; + +} + + + +inline float RadiansToDegrees(float rad) + +{ + + return rad * 180.0f / pi; + +} + + + +//------------------------------------------------------------------------// + +// Vector Class and vector functions + +//------------------------------------------------------------------------// + +class Vector { + +public: + + float x; + + float y; + + float z; + + + + Vector(void); + + Vector(float xi, float yi, float zi); + + + + float Magnitude(void); + + void Normalize(void); + + void Reverse(void); + + + + Vector& operator+=(Vector u); // vector addition + + Vector& operator-=(Vector u); // vector subtraction + + Vector& operator*=(float s); // scalar multiply + + Vector& operator/=(float s); // scalar divide + + + + Vector operator-(void); + + + +}; + + + +inline Vector operator+(Vector u, Vector v); + +inline Vector operator-(Vector u, Vector v); + +inline Vector operator^(Vector u, Vector v); + +inline float operator*(Vector u, Vector v); + +inline Vector operator*(float s, Vector u); + +inline Vector operator*(Vector u, float s); + +inline Vector operator/(Vector u, float s); + +inline float TripleScalarProduct(Vector u, Vector v, Vector w); + + + +inline Vector::Vector(void) + +{ + + x = 0; + + y = 0; + + z = 0; + +} + + + +inline Vector::Vector(float xi, float yi, float zi) + +{ + + x = xi; + + y = yi; + + z = zi; + +} + + + +inline float Vector::Magnitude(void) + +{ + + return (float) fast_sqrt(x*x + y*y + z*z); + +} + + + +inline void Vector::Normalize(void) + +{ + + float m = (float) fast_sqrt(x*x + y*y + z*z); + + if(m <= tol) m = 1; + + x /= m; + + y /= m; + + z /= m; + + + + if (fabs(x) < tol) x = 0.0f; + + if (fabs(y) < tol) y = 0.0f; + + if (fabs(z) < tol) z = 0.0f; + +} + + + +inline void Vector::Reverse(void) + +{ + + x = -x; + + y = -y; + + z = -z; + +} + + + +inline Vector& Vector::operator+=(Vector u) + +{ + + x += u.x; + + y += u.y; + + z += u.z; + + return *this; + +} + + + +inline Vector& Vector::operator-=(Vector u) + +{ + + x -= u.x; + + y -= u.y; + + z -= u.z; + + return *this; + +} + + + +inline Vector& Vector::operator*=(float s) + +{ + + x *= s; + + y *= s; + + z *= s; + + return *this; + +} + + + +inline Vector& Vector::operator/=(float s) + +{ + + x /= s; + + y /= s; + + z /= s; + + return *this; + +} + + + +inline Vector Vector::operator-(void) + +{ + + return Vector(-x, -y, -z); + +} + + + + + +inline Vector operator+(Vector u, Vector v) + +{ + + return Vector(u.x + v.x, u.y + v.y, u.z + v.z); + +} + + + +inline Vector operator-(Vector u, Vector v) + +{ + + return Vector(u.x - v.x, u.y - v.y, u.z - v.z); + +} + + + +// Vector cross product (u cross v) + +inline Vector operator^(Vector u, Vector v) + +{ + + return Vector( u.y*v.z - u.z*v.y, + + -u.x*v.z + u.z*v.x, + + u.x*v.y - u.y*v.x ); + +} + + + +// Vector dot product + +inline float operator*(Vector u, Vector v) + +{ + + return (u.x*v.x + u.y*v.y + u.z*v.z); + +} + + + +inline Vector operator*(float s, Vector u) + +{ + + return Vector(u.x*s, u.y*s, u.z*s); + +} + + + +inline Vector operator*(Vector u, float s) + +{ + + return Vector(u.x*s, u.y*s, u.z*s); + +} + + + +inline Vector operator/(Vector u, float s) + +{ + + return Vector(u.x/s, u.y/s, u.z/s); + +} + + + +// triple scalar product (u dot (v cross w)) + +inline float TripleScalarProduct(Vector u, Vector v, Vector w) + +{ + + return float( (u.x * (v.y*w.z - v.z*w.y)) + + + (u.y * (-v.x*w.z + v.z*w.x)) + + + (u.z * (v.x*w.y - v.y*w.x)) ); + + //return u*(v^w); + + + +} + + + + + + + +//------------------------------------------------------------------------// + +// Matrix Class and matrix functions + +//------------------------------------------------------------------------// + + + +class Matrix3x3 { + +public: + + // elements eij: i -> row, j -> column + + float e11, e12, e13, e21, e22, e23, e31, e32, e33; + + + + Matrix3x3(void); + + Matrix3x3( float r1c1, float r1c2, float r1c3, + + float r2c1, float r2c2, float r2c3, + + float r3c1, float r3c2, float r3c3 ); + + + + float det(void); + + Matrix3x3 Transpose(void); + + Matrix3x3 Inverse(void); + + + + Matrix3x3& operator+=(Matrix3x3 m); + + Matrix3x3& operator-=(Matrix3x3 m); + + Matrix3x3& operator*=(float s); + + Matrix3x3& operator/=(float s); + +}; + + + +inline Matrix3x3 operator+(Matrix3x3 m1, Matrix3x3 m2); + +inline Matrix3x3 operator-(Matrix3x3 m1, Matrix3x3 m2); + +inline Matrix3x3 operator/(Matrix3x3 m, float s); + +inline Matrix3x3 operator*(Matrix3x3 m1, Matrix3x3 m2); + +inline Matrix3x3 operator*(Matrix3x3 m, float s); + +inline Matrix3x3 operator*(float s, Matrix3x3 m); + +inline Vector operator*(Matrix3x3 m, Vector u); + +inline Vector operator*(Vector u, Matrix3x3 m); + + + + + + + + + + + +inline Matrix3x3::Matrix3x3(void) + +{ + + e11 = 0; + + e12 = 0; + + e13 = 0; + + e21 = 0; + + e22 = 0; + + e23 = 0; + + e31 = 0; + + e32 = 0; + + e33 = 0; + +} + + + +inline Matrix3x3::Matrix3x3( float r1c1, float r1c2, float r1c3, + + float r2c1, float r2c2, float r2c3, + + float r3c1, float r3c2, float r3c3 ) + +{ + + e11 = r1c1; + + e12 = r1c2; + + e13 = r1c3; + + e21 = r2c1; + + e22 = r2c2; + + e23 = r2c3; + + e31 = r3c1; + + e32 = r3c2; + + e33 = r3c3; + +} + + + +inline float Matrix3x3::det(void) + +{ + + return e11*e22*e33 - + + e11*e32*e23 + + + e21*e32*e13 - + + e21*e12*e33 + + + e31*e12*e23 - + + e31*e22*e13; + +} + + + +inline Matrix3x3 Matrix3x3::Transpose(void) + +{ + + return Matrix3x3(e11,e21,e31,e12,e22,e32,e13,e23,e33); + +} + + + +inline Matrix3x3 Matrix3x3::Inverse(void) + +{ + + float d = e11*e22*e33 - + + e11*e32*e23 + + + e21*e32*e13 - + + e21*e12*e33 + + + e31*e12*e23 - + + e31*e22*e13; + + + + if (d == 0) d = 1; + + + + return Matrix3x3( (e22*e33-e23*e32)/d, + + -(e12*e33-e13*e32)/d, + + (e12*e23-e13*e22)/d, + + -(e21*e33-e23*e31)/d, + + (e11*e33-e13*e31)/d, + + -(e11*e23-e13*e21)/d, + + (e21*e32-e22*e31)/d, + + -(e11*e32-e12*e31)/d, + + (e11*e22-e12*e21)/d ); + +} + + + +inline Matrix3x3& Matrix3x3::operator+=(Matrix3x3 m) + +{ + + e11 += m.e11; + + e12 += m.e12; + + e13 += m.e13; + + e21 += m.e21; + + e22 += m.e22; + + e23 += m.e23; + + e31 += m.e31; + + e32 += m.e32; + + e33 += m.e33; + + return *this; + +} + + + +inline Matrix3x3& Matrix3x3::operator-=(Matrix3x3 m) + +{ + + e11 -= m.e11; + + e12 -= m.e12; + + e13 -= m.e13; + + e21 -= m.e21; + + e22 -= m.e22; + + e23 -= m.e23; + + e31 -= m.e31; + + e32 -= m.e32; + + e33 -= m.e33; + + return *this; + +} + + + +inline Matrix3x3& Matrix3x3::operator*=(float s) + +{ + + e11 *= s; + + e12 *= s; + + e13 *= s; + + e21 *= s; + + e22 *= s; + + e23 *= s; + + e31 *= s; + + e32 *= s; + + e33 *= s; + + return *this; + +} + + + +inline Matrix3x3& Matrix3x3::operator/=(float s) + +{ + + e11 /= s; + + e12 /= s; + + e13 /= s; + + e21 /= s; + + e22 /= s; + + e23 /= s; + + e31 /= s; + + e32 /= s; + + e33 /= s; + + return *this; + +} + + + +inline Matrix3x3 operator+(Matrix3x3 m1, Matrix3x3 m2) + +{ + + return Matrix3x3( m1.e11+m2.e11, + + m1.e12+m2.e12, + + m1.e13+m2.e13, + + m1.e21+m2.e21, + + m1.e22+m2.e22, + + m1.e23+m2.e23, + + m1.e31+m2.e31, + + m1.e32+m2.e32, + + m1.e33+m2.e33); + +} + + + +inline Matrix3x3 operator-(Matrix3x3 m1, Matrix3x3 m2) + +{ + + return Matrix3x3( m1.e11-m2.e11, + + m1.e12-m2.e12, + + m1.e13-m2.e13, + + m1.e21-m2.e21, + + m1.e22-m2.e22, + + m1.e23-m2.e23, + + m1.e31-m2.e31, + + m1.e32-m2.e32, + + m1.e33-m2.e33); + +} + + + +inline Matrix3x3 operator/(Matrix3x3 m, float s) + +{ + + return Matrix3x3( m.e11/s, + + m.e12/s, + + m.e13/s, + + m.e21/s, + + m.e22/s, + + m.e23/s, + + m.e31/s, + + m.e32/s, + + m.e33/s); + +} + + + +inline Matrix3x3 operator*(Matrix3x3 m1, Matrix3x3 m2) + +{ + + return Matrix3x3( m1.e11*m2.e11 + m1.e12*m2.e21 + m1.e13*m2.e31, + + m1.e11*m2.e12 + m1.e12*m2.e22 + m1.e13*m2.e32, + + m1.e11*m2.e13 + m1.e12*m2.e23 + m1.e13*m2.e33, + + m1.e21*m2.e11 + m1.e22*m2.e21 + m1.e23*m2.e31, + + m1.e21*m2.e12 + m1.e22*m2.e22 + m1.e23*m2.e32, + + m1.e21*m2.e13 + m1.e22*m2.e23 + m1.e23*m2.e33, + + m1.e31*m2.e11 + m1.e32*m2.e21 + m1.e33*m2.e31, + + m1.e31*m2.e12 + m1.e32*m2.e22 + m1.e33*m2.e32, + + m1.e31*m2.e13 + m1.e32*m2.e23 + m1.e33*m2.e33 ); + +} + + + +inline Matrix3x3 operator*(Matrix3x3 m, float s) + +{ + + return Matrix3x3( m.e11*s, + + m.e12*s, + + m.e13*s, + + m.e21*s, + + m.e22*s, + + m.e23*s, + + m.e31*s, + + m.e32*s, + + m.e33*s); + +} + + + +inline Matrix3x3 operator*(float s, Matrix3x3 m) + +{ + + return Matrix3x3( m.e11*s, + + m.e12*s, + + m.e13*s, + + m.e21*s, + + m.e22*s, + + m.e23*s, + + m.e31*s, + + m.e32*s, + + m.e33*s); + +} + + + +inline Vector operator*(Matrix3x3 m, Vector u) + +{ + + return Vector( m.e11*u.x + m.e12*u.y + m.e13*u.z, + + m.e21*u.x + m.e22*u.y + m.e23*u.z, + + m.e31*u.x + m.e32*u.y + m.e33*u.z); + +} + + + +inline Vector operator*(Vector u, Matrix3x3 m) + +{ + + return Vector( u.x*m.e11 + u.y*m.e21 + u.z*m.e31, + + u.x*m.e12 + u.y*m.e22 + u.z*m.e32, + + u.x*m.e13 + u.y*m.e23 + u.z*m.e33); + +} + + + +//------------------------------------------------------------------------// + +// Quaternion Class and Quaternion functions + +//------------------------------------------------------------------------// + + + +class Quaternion { + +public: + + float n; // number (scalar) part + + Vector v; // vector part: v.x, v.y, v.z + + + + Quaternion(void); + + Quaternion(float e0, float e1, float e2, float e3); + + + + float Magnitude(void); + + Vector GetVector(void); + + float GetScalar(void); + + Quaternion operator+=(Quaternion q); + + Quaternion operator-=(Quaternion q); + + Quaternion operator*=(float s); + + Quaternion operator/=(float s); + + Quaternion operator~(void) const { return Quaternion(n, -v.x, -v.y, -v.z);} + +}; + + + +inline Quaternion operator+(Quaternion q1, Quaternion q2); + +inline Quaternion operator-(Quaternion q1, Quaternion q2); + +inline Quaternion operator*(Quaternion q1, Quaternion q2); + +inline Quaternion operator*(Quaternion q, float s); + +inline Quaternion operator*(float s, Quaternion q); + +inline Quaternion operator*(Quaternion q, Vector v); + +inline Quaternion operator*(Vector v, Quaternion q); + +inline Quaternion operator/(Quaternion q, float s); + +inline float QGetAngle(Quaternion q); + +inline Vector QGetAxis(Quaternion q); + +inline Quaternion QRotate(Quaternion q1, Quaternion q2); + +inline Vector QVRotate(Quaternion q, Vector v); + +inline Quaternion MakeQFromEulerAngles(float x, float y, float z); + +inline Vector MakeEulerAnglesFromQ(Quaternion q); + + + + + +inline Quaternion::Quaternion(void) + +{ + + n = 0; + + v.x = 0; + + v.y = 0; + + v.z = 0; + +} + + + +inline Quaternion::Quaternion(float e0, float e1, float e2, float e3) + +{ + + n = e0; + + v.x = e1; + + v.y = e2; + + v.z = e3; + +} + + + +inline float Quaternion::Magnitude(void) + +{ + + return (float) fast_sqrt(n*n + v.x*v.x + v.y*v.y + v.z*v.z); + +} + + + +inline Vector Quaternion::GetVector(void) + +{ + + return Vector(v.x, v.y, v.z); + +} + + + +inline float Quaternion::GetScalar(void) + +{ + + return n; + +} + + + +inline Quaternion Quaternion::operator+=(Quaternion q) + +{ + + n += q.n; + + v.x += q.v.x; + + v.y += q.v.y; + + v.z += q.v.z; + + return *this; + +} + + + +inline Quaternion Quaternion::operator-=(Quaternion q) + +{ + + n -= q.n; + + v.x -= q.v.x; + + v.y -= q.v.y; + + v.z -= q.v.z; + + return *this; + +} + + + +inline Quaternion Quaternion::operator*=(float s) + +{ + + n *= s; + + v.x *= s; + + v.y *= s; + + v.z *= s; + + return *this; + +} + + + +inline Quaternion Quaternion::operator/=(float s) + +{ + + n /= s; + + v.x /= s; + + v.y /= s; + + v.z /= s; + + return *this; + +} + + + +/*inline Quaternion Quaternion::operator~() + +{ + + return Quaternion(n, -v.x, -v.y, -v.z); + +}*/ + + + +inline Quaternion operator+(Quaternion q1, Quaternion q2) + +{ + + return Quaternion( q1.n + q2.n, + + q1.v.x + q2.v.x, + + q1.v.y + q2.v.y, + + q1.v.z + q2.v.z); + +} + + + +inline Quaternion operator-(Quaternion q1, Quaternion q2) + +{ + + return Quaternion( q1.n - q2.n, + + q1.v.x - q2.v.x, + + q1.v.y - q2.v.y, + + q1.v.z - q2.v.z); + +} + + + +inline Quaternion operator*(Quaternion q1, Quaternion q2) + +{ + + return Quaternion( q1.n*q2.n - q1.v.x*q2.v.x - q1.v.y*q2.v.y - q1.v.z*q2.v.z, + + q1.n*q2.v.x + q1.v.x*q2.n + q1.v.y*q2.v.z - q1.v.z*q2.v.y, + + q1.n*q2.v.y + q1.v.y*q2.n + q1.v.z*q2.v.x - q1.v.x*q2.v.z, + + q1.n*q2.v.z + q1.v.z*q2.n + q1.v.x*q2.v.y - q1.v.y*q2.v.x); + +} + + + +inline Quaternion operator*(Quaternion q, float s) + +{ + + return Quaternion(q.n*s, q.v.x*s, q.v.y*s, q.v.z*s); + +} + + + +inline Quaternion operator*(float s, Quaternion q) + +{ + + return Quaternion(q.n*s, q.v.x*s, q.v.y*s, q.v.z*s); + +} + + + +inline Quaternion operator*(Quaternion q, Vector v) + +{ + + return Quaternion( -(q.v.x*v.x + q.v.y*v.y + q.v.z*v.z), + + q.n*v.x + q.v.y*v.z - q.v.z*v.y, + + q.n*v.y + q.v.z*v.x - q.v.x*v.z, + + q.n*v.z + q.v.x*v.y - q.v.y*v.x); + +} + + + +inline Quaternion operator*(Vector v, Quaternion q) + +{ + + return Quaternion( -(q.v.x*v.x + q.v.y*v.y + q.v.z*v.z), + + q.n*v.x + q.v.z*v.y - q.v.y*v.z, + + q.n*v.y + q.v.x*v.z - q.v.z*v.x, + + q.n*v.z + q.v.y*v.x - q.v.x*v.y); + +} + + + +inline Quaternion operator/(Quaternion q, float s) + +{ + + return Quaternion(q.n/s, q.v.x/s, q.v.y/s, q.v.z/s); + +} + + + +inline float QGetAngle(Quaternion q) + +{ + + return (float) (2*acos(q.n)); + +} + + + +inline Vector QGetAxis(Quaternion q) + +{ + + Vector v; + + float m; + + + + v = q.GetVector(); + + m = v.Magnitude(); + + + + if (m <= tol) + + return Vector(); + + else + + return v/m; + +} + + + +inline Quaternion QRotate(Quaternion q1, Quaternion q2) + +{ + + return q1*q2*(~q1); + +} + + + +inline Vector QVRotate(Quaternion q, Vector v) + +{ + + Quaternion t; + + + + + + t = q*v*(~q); + + + + return t.GetVector(); + +} + + + +inline Quaternion MakeQFromEulerAngles(float x, float y, float z) + +{ + + Quaternion q; + + double roll = DegreesToRadians(x); + + double pitch = DegreesToRadians(y); + + double yaw = DegreesToRadians(z); + + + + double cyaw, cpitch, croll, syaw, spitch, sroll; + + double cyawcpitch, syawspitch, cyawspitch, syawcpitch; + + + + cyaw = cos(0.5f * yaw); + + cpitch = cos(0.5f * pitch); + + croll = cos(0.5f * roll); + + syaw = sin(0.5f * yaw); + + spitch = sin(0.5f * pitch); + + sroll = sin(0.5f * roll); + + + + cyawcpitch = cyaw*cpitch; + + syawspitch = syaw*spitch; + + cyawspitch = cyaw*spitch; + + syawcpitch = syaw*cpitch; + + + + q.n = (float) (cyawcpitch * croll + syawspitch * sroll); + + q.v.x = (float) (cyawcpitch * sroll - syawspitch * croll); + + q.v.y = (float) (cyawspitch * croll + syawcpitch * sroll); + + q.v.z = (float) (syawcpitch * croll - cyawspitch * sroll); + + + + return q; + +} + + + +inline Vector MakeEulerAnglesFromQ(Quaternion q) + +{ + + double r11, r21, r31, r32, r33, r12, r13; + + double q00, q11, q22, q33; + + double tmp; + + Vector u; + + + + q00 = q.n * q.n; + + q11 = q.v.x * q.v.x; + + q22 = q.v.y * q.v.y; + + q33 = q.v.z * q.v.z; + + + + r11 = q00 + q11 - q22 - q33; + + r21 = 2 * (q.v.x*q.v.y + q.n*q.v.z); + + r31 = 2 * (q.v.x*q.v.z - q.n*q.v.y); + + r32 = 2 * (q.v.y*q.v.z + q.n*q.v.x); + + r33 = q00 - q11 - q22 + q33; + + + + tmp = fabs(r31); + + if(tmp > 0.999999) + + { + + r12 = 2 * (q.v.x*q.v.y - q.n*q.v.z); + + r13 = 2 * (q.v.x*q.v.z + q.n*q.v.y); + + + + u.x = RadiansToDegrees(0.0f); //roll + + u.y = RadiansToDegrees((float) (-(pi/2) * r31/tmp)); // pitch + + u.z = RadiansToDegrees((float) atan2(-r12, -r31*r13)); // yaw + + return u; + + } + + + + u.x = RadiansToDegrees((float) atan2(r32, r33)); // roll + + u.y = RadiansToDegrees((float) asin(-r31)); // pitch + + u.z = RadiansToDegrees((float) atan2(r21, r11)); // yaw + + return u; + + + + + +} + + + + + + + + + + + +#endif + diff --git a/blackshades_revenge/Source/Quaternions.cpp b/blackshades_revenge/Source/Quaternions.cpp new file mode 100644 index 0000000..6122480 --- /dev/null +++ b/blackshades_revenge/Source/Quaternions.cpp @@ -0,0 +1,752 @@ +#include "Quaternions.h" + +// Functions +quaternion Quat_Mult(quaternion q1, quaternion q2) +{ + quaternion QResult; + float a, b, c, d, e, f, g, h; + a = (q1.w + q1.x) * (q2.w + q2.x); + b = (q1.z - q1.y) * (q2.y - q2.z); + c = (q1.w - q1.x) * (q2.y + q2.z); + d = (q1.y + q1.z) * (q2.w - q2.x); + e = (q1.x + q1.z) * (q2.x + q2.y); + f = (q1.x - q1.z) * (q2.x - q2.y); + g = (q1.w + q1.y) * (q2.w - q2.z); + h = (q1.w - q1.y) * (q2.w + q2.z); + QResult.w = b + (-e - f + g + h) / 2; + QResult.x = a - (e + f + g + h) / 2; + QResult.y = c + (e - f + g - h) / 2; + QResult.z = d + (e - f - g + h) / 2; + return QResult; +} + +XYZ XYZ::operator+(XYZ add){ + XYZ ne; + ne=add; + ne.x+=x; + ne.y+=y; + ne.z+=z; + return ne; +} + +XYZ XYZ::operator-(XYZ add){ + XYZ ne; + ne=add; + ne.x=x-ne.x; + ne.y=y-ne.y; + ne.z=z-ne.z; + return ne; +} + +XYZ XYZ::operator*(float add){ + XYZ ne; + ne.x=x*add; + ne.y=y*add; + ne.z=z*add; + return ne; +} + +XYZ XYZ::operator*(XYZ add){ + XYZ ne; + ne.x=x*add.x; + ne.y=y*add.y; + ne.z=z*add.z; + return ne; +} + +XYZ XYZ::operator/(float add){ + XYZ ne; + ne.x=x/add; + ne.y=y/add; + ne.z=z/add; + return ne; +} + +void XYZ::operator+=(XYZ add){ + x+=add.x; + y+=add.y; + z+=add.z; +} + +void XYZ::operator-=(XYZ add){ + x=x-add.x; + y=y-add.y; + z=z-add.z; +} + +void XYZ::operator*=(float add){ + x=x*add; + y=y*add; + z=z*add; +} + +void XYZ::operator*=(XYZ add){ + x=x*add.x; + y=y*add.y; + z=z*add.z; +} + +void XYZ::operator/=(float add){ + x=x/add; + y=y/add; + z=z/add; +} + +void XYZ::operator=(float add){ + x=add; + y=add; + z=add; +} + +void XYZ::vec(Vector add){ + x=add.x; + y=add.y; + z=add.z; +} + +bool XYZ::operator==(XYZ add){ + if(x==add.x&&y==add.y&&z==add.z)return 1; + return 0; +} + +quaternion To_Quat(Matrix_t m) +{ + // From Jason Shankel, (C) 2000. + quaternion Quat; + + float Tr = m[0][0] + m[1][1] + m[2][2] + 1.0f, fourD; + float q[4]; + + int i,j,k; + if (Tr >= 1.0) + { + fourD = 2.0f*fast_sqrt(Tr); + q[3] = fourD/4.0f; + q[0] = (m[2][1] - m[1][2]) / fourD; + q[1] = (m[0][2] - m[2][0]) / fourD; + q[2] = (m[1][0] - m[0][1]) / fourD; + } + else + { + if (m[0][0] > m[1][1]) + { + i = 0; + } + else + { + i = 1; + } + if (m[2][2] > m[i][i]) + { + i = 2; + } + j = (i+1)%3; + k = (j+1)%3; + fourD = 2.0f*fast_sqrt(m[i][i] - m[j][j] - m[k][k] + 1.0f); + q[i] = fourD / 4.0f; + q[j] = (m[j][i] + m[i][j]) / fourD; + q[k] = (m[k][i] + m[i][k]) / fourD; + q[3] = (m[j][k] - m[k][j]) / fourD; + } + + Quat.x = q[0]; + Quat.y = q[1]; + Quat.z = q[2]; + Quat.w = q[3]; + return Quat; +} +void Quat_2_Matrix(quaternion Quat, Matrix_t m) +{ + // From the GLVelocity site (http://glvelocity.gamedev.net) + float fW = Quat.w; + float fX = Quat.x; + float fY = Quat.y; + float fZ = Quat.z; + float fXX = fX * fX; + float fYY = fY * fY; + float fZZ = fZ * fZ; + m[0][0] = 1.0f - 2.0f * (fYY + fZZ); + m[1][0] = 2.0f * (fX * fY + fW * fZ); + m[2][0] = 2.0f * (fX * fZ - fW * fY); + m[3][0] = 0.0f; + m[0][1] = 2.0f * (fX * fY - fW * fZ); + m[1][1] = 1.0f - 2.0f * (fXX + fZZ); + m[2][1] = 2.0f * (fY * fZ + fW * fX); + m[3][1] = 0.0f; + m[0][2] = 2.0f * (fX * fZ + fW * fY); + m[1][2] = 2.0f * (fX * fZ - fW * fX); + m[2][2] = 1.0f - 2.0f * (fXX + fYY); + m[3][2] = 0.0f; + m[0][3] = 0.0f; + m[1][3] = 0.0f; + m[2][3] = 0.0f; + m[3][3] = 1.0f; +} +quaternion To_Quat(angle_axis Ang_Ax) +{ + // From the Quaternion Powers article on gamedev.net + quaternion Quat; + + Quat.x = Ang_Ax.x * sinf(Ang_Ax.angle / 2); + Quat.y = Ang_Ax.y * sinf(Ang_Ax.angle / 2); + Quat.z = Ang_Ax.z * sinf(Ang_Ax.angle / 2); + Quat.w = cosf(Ang_Ax.angle / 2); + return Quat; +} +angle_axis Quat_2_AA(quaternion Quat) +{ + angle_axis Ang_Ax; + float scale, tw; + tw = (float)acos(Quat.w) * 2; + scale = (float)sin(tw / 2.0); + Ang_Ax.x = Quat.x / scale; + Ang_Ax.y = Quat.y / scale; + Ang_Ax.z = Quat.z / scale; + + Ang_Ax.angle = 2.0f * acosf(Quat.w)/(float)PI*180; + return Ang_Ax; +} + +quaternion To_Quat(int In_Degrees, euler Euler) +{ + // From the gamasutra quaternion article + quaternion Quat; + float cr, cp, cy, sr, sp, sy, cpcy, spsy; + //If we are in Degree mode, convert to Radians + if (In_Degrees) { + Euler.x = Euler.x * (float)PI / 180; + Euler.y = Euler.y * (float)PI / 180; + Euler.z = Euler.z * (float)PI / 180; + } + //Calculate trig identities + //Formerly roll, pitch, yaw + cr = float(cos(Euler.x/2)); + cp = float(cos(Euler.y/2)); + cy = float(cos(Euler.z/2)); + sr = float(sin(Euler.x/2)); + sp = float(sin(Euler.y/2)); + sy = float(sin(Euler.z/2)); + + cpcy = cp * cy; + spsy = sp * sy; + Quat.w = cr * cpcy + sr * spsy; + Quat.x = sr * cpcy - cr * spsy; + Quat.y = cr * sp * cy + sr * cp * sy; + Quat.z = cr * cp * sy - sr * sp * cy; + + return Quat; +} + +quaternion QNormalize(quaternion Quat) +{ + float norm; + norm = Quat.x * Quat.x + + Quat.y * Quat.y + + Quat.z * Quat.z + + Quat.w * Quat.w; + Quat.x = float(Quat.x / norm); + Quat.y = float(Quat.y / norm); + Quat.z = float(Quat.z / norm); + Quat.w = float(Quat.w / norm); + return Quat; +} + +XYZ Quat2Vector(quaternion Quat) +{ + QNormalize(Quat); + + float fW = Quat.w; + float fX = Quat.x; + float fY = Quat.y; + float fZ = Quat.z; + + XYZ tempvec; + + tempvec.x = 2.0f*(fX*fZ-fW*fY); + tempvec.y = 2.0f*(fY*fZ+fW*fX); + tempvec.z = 1.0f-2.0f*(fX*fX+fY*fY); + + return tempvec; +} + +void CrossProduct(XYZ P, XYZ Q, XYZ *V){ + V->x = P.y * Q.z - P.z * Q.y; + V->y = P.z * Q.x - P.x * Q.z; + V->z = P.x * Q.y - P.y * Q.x; +} + +void Normalise(XYZ *vectory) { + float d = fast_sqrt(vectory->x*vectory->x+vectory->y*vectory->y+vectory->z*vectory->z); + if(d==0){return;} + vectory->x /= d; + vectory->y /= d; + vectory->z /= d; +} + +float fast_sqrt (register float arg) +{ +#ifdef OS9 + // Can replace with slower return std::sqrt(arg); + register float result; + + if (arg == 0.0) return 0.0; + + asm { + frsqrte result,arg // Calculate Square root + } + + // Newton Rhapson iterations. + result = result + 0.5 * result * (1.0 - arg * result * result); + result = result + 0.5 * result * (1.0 - arg * result * result); + + return result * arg; +#else + return sqrtf(arg); +#endif +} + +float normaldotproduct(XYZ point1, XYZ point2){ + GLfloat returnvalue; + Normalise(&point1); + Normalise(&point2); + returnvalue=(point1.x*point2.x+point1.y*point2.y+point1.z*point2.z); + return returnvalue; +} + +extern float u0, u1, u2; +extern float v0, v1, v2; +extern float a, b; +extern float max; +extern int i, j; +extern bool bInter; +extern float pointv[3]; +extern float p1v[3]; +extern float p2v[3]; +extern float p3v[3]; +extern float normalv[3]; + +bool PointInTriangle(Vector *p, Vector normal, float p11, float p12, float p13, float p21, float p22, float p23, float p31, float p32, float p33) +{ + bInter=0; + + pointv[0]=p->x; + pointv[1]=p->y; + pointv[2]=p->z; + + + p1v[0]=p11; + p1v[1]=p12; + p1v[2]=p13; + + p2v[0]=p21; + p2v[1]=p22; + p2v[2]=p23; + + p3v[0]=p31; + p3v[1]=p32; + p3v[2]=p33; + + normalv[0]=normal.x; + normalv[1]=normal.y; + normalv[2]=normal.z; + +#define ABS(X) (((X)<0.f)?-(X):(X) ) +#define MAX(A, B) (((A)<(B))?(B):(A)) + max = MAX(MAX(ABS(normalv[0]), ABS(normalv[1])), ABS(normalv[2])); +#undef MAX + if (max == ABS(normalv[0])) {i = 1; j = 2;} // y, z + if (max == ABS(normalv[1])) {i = 0; j = 2;} // x, z + if (max == ABS(normalv[2])) {i = 0; j = 1;} // x, y +#undef ABS + + u0 = pointv[i] - p1v[i]; + v0 = pointv[j] - p1v[j]; + u1 = p2v[i] - p1v[i]; + v1 = p2v[j] - p1v[j]; + u2 = p3v[i] - p1v[i]; + v2 = p3v[j] - p1v[j]; + + if (u1 > -1.0e-05f && u1 < 1.0e-05f)// == 0.0f) + { + b = u0 / u2; + if (0.0f <= b && b <= 1.0f) + { + a = (v0 - b * v2) / v1; + if ((a >= 0.0f) && (( a + b ) <= 1.0f)) + bInter = 1; + } + } + else + { + b = (v0 * u1 - u0 * v1) / (v2 * u1 - u2 * v1); + if (0.0f <= b && b <= 1.0f) + { + a = (u0 - b * u2) / u1; + if ((a >= 0.0f) && (( a + b ) <= 1.0f )) + bInter = 1; + } + } + + return bInter; +} + +bool LineFacet(Vector p1,Vector p2,Vector pa,Vector pb,Vector pc,Vector *p) +{ + float d; + //float a1,a2,a3; + //float total,denom,mu; + float denom,mu; + Vector n,pa1,pa2,pa3; + + //Calculate the parameters for the plane + n.x = (pb.y - pa.y)*(pc.z - pa.z) - (pb.z - pa.z)*(pc.y - pa.y); + n.y = (pb.z - pa.z)*(pc.x - pa.x) - (pb.x - pa.x)*(pc.z - pa.z); + n.z = (pb.x - pa.x)*(pc.y - pa.y) - (pb.y - pa.y)*(pc.x - pa.x); + n.Normalize(); + d = - n.x * pa.x - n.y * pa.y - n.z * pa.z; + + //Calculate the position on the line that intersects the plane + denom = n.x * (p2.x - p1.x) + n.y * (p2.y - p1.y) + n.z * (p2.z - p1.z); + if (fabs(denom) < 0.0000001f) // Line and plane don't intersect + return 0; + mu = - (d + n.x * p1.x + n.y * p1.y + n.z * p1.z) / denom; + p->x = p1.x + mu * (p2.x - p1.x); + p->y = p1.y + mu * (p2.y - p1.y); + p->z = p1.z + mu * (p2.z - p1.z); + if (mu < 0 || mu > 1) // Intersection not along line segment + return 0; + + if(!PointInTriangle( p, n, pa.x, pa.y, pa.z, pb.x, pb.y, pb.z, pc.x, pc.y, pc.z)){return 0;} + + return 1; +} + +bool PointInTriangle(XYZ *p, XYZ normal, XYZ *p1, XYZ *p2, XYZ *p3) +{ + bInter=0; + + pointv[0]=p->x; + pointv[1]=p->y; + pointv[2]=p->z; + + + p1v[0]=p1->x; + p1v[1]=p1->y; + p1v[2]=p1->z; + + p2v[0]=p2->x; + p2v[1]=p2->y; + p2v[2]=p2->z; + + p3v[0]=p3->x; + p3v[1]=p3->y; + p3v[2]=p3->z; + + normalv[0]=normal.x; + normalv[1]=normal.y; + normalv[2]=normal.z; + +#define ABS(X) (((X)<0.f)?-(X):(X) ) +#define MAX(A, B) (((A)<(B))?(B):(A)) + max = MAX(MAX(ABS(normalv[0]), ABS(normalv[1])), ABS(normalv[2])); +#undef MAX + if (max == ABS(normalv[0])) {i = 1; j = 2;} // y, z + if (max == ABS(normalv[1])) {i = 0; j = 2;} // x, z + if (max == ABS(normalv[2])) {i = 0; j = 1;} // x, y +#undef ABS + + u0 = pointv[i] - p1v[i]; + v0 = pointv[j] - p1v[j]; + u1 = p2v[i] - p1v[i]; + v1 = p2v[j] - p1v[j]; + u2 = p3v[i] - p1v[i]; + v2 = p3v[j] - p1v[j]; + + if (u1 > -1.0e-05f && u1 < 1.0e-05f)// == 0.0f) + { + b = u0 / u2; + if (0.0f <= b && b <= 1.0f) + { + a = (v0 - b * v2) / v1; + if ((a >= 0.0f) && (( a + b ) <= 1.0f)) + bInter = 1; + } + } + else + { + b = (v0 * u1 - u0 * v1) / (v2 * u1 - u2 * v1); + if (0.0f <= b && b <= 1.0f) + { + a = (u0 - b * u2) / u1; + if ((a >= 0.0f) && (( a + b ) <= 1.0f )) + bInter = 1; + } + } + + return bInter; +} + +bool LineFacet(XYZ p1,XYZ p2,XYZ pa,XYZ pb,XYZ pc,XYZ *p) +{ + float d; + //float a1,a2,a3; + //float total,denom,mu; + float denom,mu; + //XYZ n,pa1,pa2,pa3; + XYZ n; + + //Calculate the parameters for the plane + n.x = (pb.y - pa.y)*(pc.z - pa.z) - (pb.z - pa.z)*(pc.y - pa.y); + n.y = (pb.z - pa.z)*(pc.x - pa.x) - (pb.x - pa.x)*(pc.z - pa.z); + n.z = (pb.x - pa.x)*(pc.y - pa.y) - (pb.y - pa.y)*(pc.x - pa.x); + Normalise(&n); + d = - n.x * pa.x - n.y * pa.y - n.z * pa.z; + + //Calculate the position on the line that intersects the plane + denom = n.x * (p2.x - p1.x) + n.y * (p2.y - p1.y) + n.z * (p2.z - p1.z); + if (fabs(denom) < 0.0000001f) // Line and plane don't intersect + return 0; + mu = - (d + n.x * p1.x + n.y * p1.y + n.z * p1.z) / denom; + p->x = p1.x + mu * (p2.x - p1.x); + p->y = p1.y + mu * (p2.y - p1.y); + p->z = p1.z + mu * (p2.z - p1.z); + if (mu < 0 || mu > 1) // Intersection not along line segment + return 0; + + if(!PointInTriangle( p, n, &pa, &pb, &pc)){return 0;} + + return 1; +} + +extern float d; +extern float a1,a2,a3; +extern float total,denom,mu; +extern XYZ pa1,pa2,pa3,n; + +float LineFacetd(XYZ p1,XYZ p2,XYZ pa,XYZ pb,XYZ pc,XYZ *p) +{ + + //Calculate the parameters for the plane + n.x = (pb.y - pa.y)*(pc.z - pa.z) - (pb.z - pa.z)*(pc.y - pa.y); + n.y = (pb.z - pa.z)*(pc.x - pa.x) - (pb.x - pa.x)*(pc.z - pa.z); + n.z = (pb.x - pa.x)*(pc.y - pa.y) - (pb.y - pa.y)*(pc.x - pa.x); + Normalise(&n); + d = - n.x * pa.x - n.y * pa.y - n.z * pa.z; + + //Calculate the position on the line that intersects the plane + denom = n.x * (p2.x - p1.x) + n.y * (p2.y - p1.y) + n.z * (p2.z - p1.z); + if (fabs(denom) < 0.0000001f) // Line and plane don't intersect + return 0; + mu = - (d + n.x * p1.x + n.y * p1.y + n.z * p1.z) / denom; + p->x = p1.x + mu * (p2.x - p1.x); + p->y = p1.y + mu * (p2.y - p1.y); + p->z = p1.z + mu * (p2.z - p1.z); + if (mu < 0 || mu > 1) // Intersection not along line segment + return 0; + + if(!PointInTriangle( p, n, &pa, &pb, &pc)){return 0;} + + return 1; +} + +float LineFacetd(XYZ p1,XYZ p2,XYZ pa,XYZ pb,XYZ pc, XYZ n, XYZ *p) +{ + + //Calculate the parameters for the plane + d = - n.x * pa.x - n.y * pa.y - n.z * pa.z; + + //Calculate the position on the line that intersects the plane + denom = n.x * (p2.x - p1.x) + n.y * (p2.y - p1.y) + n.z * (p2.z - p1.z); + if (fabs(denom) < 0.0000001f) // Line and plane don't intersect + return 0; + mu = - (d + n.x * p1.x + n.y * p1.y + n.z * p1.z) / denom; + p->x = p1.x + mu * (p2.x - p1.x); + p->y = p1.y + mu * (p2.y - p1.y); + p->z = p1.z + mu * (p2.z - p1.z); + if (mu < 0 || mu > 1) // Intersection not along line segment + return 0; + + if(!PointInTriangle( p, n, &pa, &pb, &pc)){return 0;} + return 1; +} + +float LineFacetd(XYZ *p1,XYZ *p2,XYZ *pa,XYZ *pb,XYZ *pc, XYZ *n, XYZ *p) +{ + + //Calculate the parameters for the plane + d = - n->x * pa->x - n->y * pa->y - n->z * pa->z; + + //Calculate the position on the line that intersects the plane + denom = n->x * (p2->x - p1->x) + n->y * (p2->y - p1->y) + n->z * (p2->z - p1->z); + if (fabs(denom) < 0.0000001f) // Line and plane don't intersect + return 0; + mu = - (d + n->x * p1->x + n->y * p1->y + n->z * p1->z) / denom; + p->x = p1->x + mu * (p2->x - p1->x); + p->y = p1->y + mu * (p2->y - p1->y); + p->z = p1->z + mu * (p2->z - p1->z); + if (mu < 0 || mu > 1) // Intersection not along line segment + return 0; + + if(!PointInTriangle( p, *n, pa, pb, pc)){return 0;} + return 1; +} + +void ReflectVector(XYZ *vel, XYZ *n) +{ + XYZ vn; + XYZ vt; + float dotprod; + + dotprod=dotproduct(*n,*vel); + vn.x=n->x*dotprod; + vn.y=n->y*dotprod; + vn.z=n->z*dotprod; + + vt.x=vel->x-vn.x; + vt.y=vel->y-vn.y; + vt.z=vel->z-vn.z; + + vel->x = vt.x - vn.x; + vel->y = vt.y - vn.y; + vel->z = vt.z - vn.z; +} + +float dotproduct(XYZ point1, XYZ point2){ + GLfloat returnvalue; + returnvalue=(point1.x*point2.x+point1.y*point2.y+point1.z*point2.z); + return returnvalue; +} + +float findDistance(XYZ point1, XYZ point2){ + return(fast_sqrt((point1.x-point2.x)*(point1.x-point2.x)+(point1.y-point2.y)*(point1.y-point2.y)+(point1.z-point2.z)*(point1.z-point2.z))); +} + +float findLength(XYZ point1){ + return(fast_sqrt((point1.x)*(point1.x)+(point1.y)*(point1.y)+(point1.z)*(point1.z))); +} + + +float findLengthfast(XYZ point1){ + return((point1.x)*(point1.x)+(point1.y)*(point1.y)+(point1.z)*(point1.z)); +} + +float findDistancefast(XYZ point1, XYZ point2){ + return((point1.x-point2.x)*(point1.x-point2.x)+(point1.y-point2.y)*(point1.y-point2.y)+(point1.z-point2.z)*(point1.z-point2.z)); +} + +XYZ DoRotation(XYZ thePoint, float xang, float yang, float zang){ + XYZ newpoint; + if(xang){ + xang*=6.283185f; + xang/=360; + } + if(yang){ + yang*=6.283185f; + yang/=360; + } + if(zang){ + zang*=6.283185f; + zang/=360; + } + + + if(yang){ + newpoint.z=thePoint.z*cosf(yang)-thePoint.x*sinf(yang); + newpoint.x=thePoint.z*sinf(yang)+thePoint.x*cosf(yang); + thePoint.z=newpoint.z; + thePoint.x=newpoint.x; + } + + if(zang){ + newpoint.x=thePoint.x*cosf(zang)-thePoint.y*sinf(zang); + newpoint.y=thePoint.y*cosf(zang)+thePoint.x*sinf(zang); + thePoint.x=newpoint.x; + thePoint.y=newpoint.y; + } + + if(xang){ + newpoint.y=thePoint.y*cosf(xang)-thePoint.z*sinf(xang); + newpoint.z=thePoint.y*sinf(xang)+thePoint.z*cosf(xang); + thePoint.z=newpoint.z; + thePoint.y=newpoint.y; + } + + return thePoint; +} + +float square( float f ) { return (f*f) ;} + +bool sphere_line_intersection ( + float x1, float y1 , float z1, + float x2, float y2 , float z2, + float x3, float y3 , float z3, float r ) +{ + + // x1,y1,z1 P1 coordinates (point of line) + // x2,y2,z2 P2 coordinates (point of line) + // x3,y3,z3, r P3 coordinates and radius (sphere) + // x,y,z intersection coordinates + // + // This function returns a pointer array which first index indicates + // the number of intersection point, followed by coordinate pairs. + +// float x , y , z; + //float mu; + float a, b, c, i ; + + if(x1>x3+r&&x2>x3+r)return(0); + if(x1y3+r&&y2>y3+r)return(0); + if(y1z3+r&&z2>z3+r)return(0); + if(z1 +#endif + +#include "Maths.h" +#ifdef OS9 +#include +#else +#include +#endif +#include "PhysicsMath.h" + +/**> Quaternion Structures <**/ +#define PI 3.14159265355555897932384626 +#define RADIANS 0 +#define DEGREES 1 +#define deg2rad .0174532925 + +//using namespace std; +typedef float Matrix_t [4][4]; +struct euler +{ + float x, y, z; +}; +struct angle_axis +{ + float x, y, z, angle; +}; +struct quaternion +{ + float x, y, z, w; +}; + +class XYZ{ + public: + float x; + float y; + float z; + XYZ operator+(XYZ add); + XYZ operator-(XYZ add); + XYZ operator*(float add); + XYZ operator*(XYZ add); + XYZ operator/(float add); + void operator+=(XYZ add); + void operator-=(XYZ add); + void operator*=(float add); + void operator*=(XYZ add); + void operator/=(float add); + void operator=(float add); + void vec(Vector add); + bool operator==(XYZ add); +}; + +/*********************> Quaternion Function definition <********/ +quaternion To_Quat(int Degree_Flag, euler Euler); +quaternion To_Quat(angle_axis Ang_Ax); +quaternion To_Quat(Matrix_t m); +angle_axis Quat_2_AA(quaternion Quat); +void Quat_2_Matrix(quaternion Quat, Matrix_t m); +quaternion Normalize(quaternion Quat); +quaternion Quat_Mult(quaternion q1, quaternion q2); +quaternion QNormalize(quaternion Quat); +XYZ Quat2Vector(quaternion Quat); + +void CrossProduct(XYZ P, XYZ Q, XYZ *V); +void Normalise(XYZ *vectory); +float normaldotproduct(XYZ point1, XYZ point2); +float fast_sqrt (register float arg); +bool PointInTriangle(XYZ *p, XYZ normal, XYZ *p1, XYZ *p2, XYZ *p3); +bool LineFacet(XYZ p1,XYZ p2,XYZ pa,XYZ pb,XYZ pc,XYZ *p); +float LineFacetd(XYZ p1,XYZ p2,XYZ pa,XYZ pb,XYZ pc,XYZ *p); +float LineFacetd(XYZ p1,XYZ p2,XYZ pa,XYZ pb,XYZ pc,XYZ n, XYZ *p); +float LineFacetd(XYZ *p1,XYZ *p2,XYZ *pa,XYZ *pb,XYZ *pc,XYZ *n, XYZ *p); +bool PointInTriangle(Vector *p, Vector normal, float p11, float p12, float p13, float p21, float p22, float p23, float p31, float p32, float p33); +bool LineFacet(Vector p1,Vector p2,Vector pa,Vector pb,Vector pc,Vector *p); +void ReflectVector(XYZ *vel, XYZ *n); +XYZ DoRotation(XYZ thePoint, float xang, float yang, float zang); +XYZ DoRotationRadian(XYZ thePoint, float xang, float yang, float zang); +float findDistance(XYZ point1, XYZ point2); +float findLength(XYZ point1); +float findLengthfast(XYZ point1); +float findDistancefast(XYZ point1, XYZ point2); +float dotproduct(XYZ point1, XYZ point2); +bool sphere_line_intersection ( + float x1, float y1 , float z1, + float x2, float y2 , float z2, + float x3, float y3 , float z3, float r ); + +#endif + diff --git a/blackshades_revenge/Source/Serialize.cpp b/blackshades_revenge/Source/Serialize.cpp new file mode 100644 index 0000000..67b98a6 --- /dev/null +++ b/blackshades_revenge/Source/Serialize.cpp @@ -0,0 +1,114 @@ +#ifdef __linux__ +#include +#endif + +#include "Models.h" +#include "Quaternions.h" +#include "Serialize.h" + +/* these all read big-endian data */ + +// WARNING, MASSIVELY SUBOPTIMAL. + +int ReadBool(FILE *fd, int count, bool *b) +{ + while (count--) { + unsigned char buf[1]; + +// if (read(fd, buf, 1) != 1) { + if (fread(buf, 1, 1, fd) != 1) { + STUB_FUNCTION; + } + + *b = (buf[0] != 0) ? true : false; + + b++; + } + + return 1; +} + +int ReadShort(FILE *fd, int count, short *s) +{ + while (count--) { + unsigned char buf[2]; + + //if (read(fd, buf, 2) != 2) { + if (fread(buf, 2, 1, fd) != 1) { + STUB_FUNCTION; + } + + *s = (short)((buf[0] << 8) | buf[1]); + + s++; + } + + return 1; +} + +int ReadInt(FILE *fd, int count, int *s) +{ + while (count--) { + unsigned char buf[4]; + + //if (read(fd, buf, 4) != 4) { + if (fread(buf, 4, 1, fd) != 1) { + STUB_FUNCTION; + } + + *s = (int)((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]); + + s++; + } + + return 1; +} + +union intfloat { + int i; + float f; +} intfloat; + +int ReadFloat(FILE *fd, int count, float *f) +{ + union intfloat infl; + + while (count--) { + ReadInt(fd, 1, &(infl.i)); + + *f = infl.f; + + f++; + } + + return 1; +} + +int ReadXYZ(FILE *fd, int count, XYZ *xyz) +{ + while (count--) { + ReadFloat(fd, 1, &(xyz->x)); + ReadFloat(fd, 1, &(xyz->y)); + ReadFloat(fd, 1, &(xyz->z)); + + xyz++; + } + + return 1; +} + +int ReadTexturedTriangle(FILE *fd, int count, TexturedTriangle *tt) +{ + while (count--) { + short pad; + ReadShort(fd, 3, tt->vertex); + ReadShort(fd, 1, &pad); /* crud */ + ReadFloat(fd, 1, &(tt->r)); + ReadFloat(fd, 1, &(tt->g)); + ReadFloat(fd, 1, &(tt->b)); + + tt++; + } + + return count; +} diff --git a/blackshades_revenge/Source/Serialize.h b/blackshades_revenge/Source/Serialize.h new file mode 100644 index 0000000..9fcea41 --- /dev/null +++ b/blackshades_revenge/Source/Serialize.h @@ -0,0 +1,13 @@ +#ifndef SERIALIZE_H +#define SERIALIZE_H + +/* these all read big-endian data */ + +int ReadBool(FILE *fd, int count, bool *b); +int ReadShort(FILE *fd, int count, short *s); +int ReadInt(FILE *fd, int count, int *s); +int ReadFloat(FILE *fd, int count, float *f); +int ReadXYZ(FILE *fd, int count, XYZ *xyz); +int ReadTexturedTriangle(FILE *fd, int count, TexturedTriangle *tt); + +#endif diff --git a/blackshades_revenge/Source/Skeleton.cpp b/blackshades_revenge/Source/Skeleton.cpp new file mode 100644 index 0000000..2f30158 --- /dev/null +++ b/blackshades_revenge/Source/Skeleton.cpp @@ -0,0 +1,866 @@ +/**> HEADER FILES <**/ +#include "Skeleton.h" + +#include "Serialize.h" + +#include "SoundFX.h" + +extern double multiplier; +extern unsigned int gSourceID[100]; +extern unsigned int gSampleSet[100]; +extern int visions; +extern float rad2deg; +extern Camera camera; +extern float soundscalefactor; + +extern XYZ vel; +extern XYZ midp; +extern XYZ newpoint1,newpoint2; + +extern float oldlength; +extern float relaxlength; + +extern float friction; +extern int numrepeats; +extern float groundlevel; +extern float offset; +extern XYZ impact; +extern XYZ overpoint; +extern XYZ underpoint; +extern int whichtri; +extern XYZ normalrotated; +extern bool groundish; + + +void Joint::DoConstraint() +{ + + if(hasparent){ + //Find midpoint + midp=(position+parent->position)/2; + //Find vector from midpoint to second vector + vel=parent->position-midp; + //Change to unit vector + Normalise(&vel); + //Apply velocity change + velocity+=((midp-vel*length/2)-position); + parent->velocity+=((midp+vel*length/2)-parent->position); + //Move child point to within certain distance of parent point + if(!locked)position=midp-vel*length/2; + if(!parent->locked)parent->position=midp+vel*length/2; + } +} + +void Muscle::DoConstraint(int broken) +{ + oldlength=length; + relaxlength=findDistance(parent1->position,parent2->position); + + if(type==boneconnect)strength=1; + if(type==constraint)strength=0; + + if(strength<0)strength=0; + if(strength>1)strength=1; + + length-=(length-relaxlength)*(1-strength)*multiplier*multiplier*10000; + length-=(length-targetlength)*(strength)*multiplier*multiplier*10000; + if(strength==0)length=relaxlength; + + if((relaxlength-length>0&&relaxlength-oldlength<0)||(relaxlength-length<0&&relaxlength-oldlength>0))length=relaxlength; + + if(lengthmaxlength&&!broken)length=maxlength; + + //Find midpoint + midp=(parent1->position+parent2->position)/2; + //Find vector from midpoint to second vector + vel=parent2->position-midp; + //Change to unit vector + Normalise(&vel); + //Apply velocity change + newpoint1=midp-vel*length/2; + newpoint2=midp+vel*length/2; + parent1->velocity+=(newpoint1-parent1->position); + parent2->velocity+=(newpoint2-parent2->position); + //Move child point to within certain distance of parent point + if(!parent1->locked)parent1->position=newpoint1; + if(!parent2->locked)parent2->position=newpoint2; +} + +Skeleton::Skeleton() : m_bodyland(false), m_headland(false) +{ + +} + +void Skeleton::DoConstraints() +{ + numrepeats=3; + + for(int j=0; jy+=.35f; + + for(int j=0; jLineCheck2(overpoint,underpoint,&impact,*move,rotation); + if(collide->normals[whichtri].y<=.8)whichtri=collide->LineCheck2(joints[i].realoldposition,joints[i].position,&impact,*move,rotation); + if(joints[i].position.y<=groundlevel+offset||whichtri!=-1){ + if(whichtri==-1||(whichtri!=-1&&collide->normals[whichtri].y>.8)){ + if(whichtri==-1)joints[i].position.y=groundlevel+offset; + if(whichtri!=-1){ + joints[i].position=impact; + joints[i].position.y+=offset; + } + joints[i].velocity.y*=-.3f; + joints[i].velocity.x*=.3f; + joints[i].velocity.z*=.3f; + } + offset =.2f; + if(whichtri!=-1&&collide->normals[whichtri].y<=.8f){ + normalrotated=DoRotation(collide->normals[whichtri],0,rotation,0); + joints[i].position=impact+normalrotated*offset; + ReflectVector(&joints[i].velocity,&normalrotated); + joints[i].velocity*=.3f; + } + if(broken<=1){ + XYZ avgvelocity; + avgvelocity=0; + float gLoc[3]; + //ALint tempint; + for(int k=0; k2||findLengthfast(avgvelocity)>2)){ + avgvelocity+=joints[i].velocity; + gLoc[0]=joints[i].position.x/soundscalefactor; + gLoc[1]=joints[i].position.y/soundscalefactor; + gLoc[2]=joints[i].position.z/soundscalefactor; + + /* +#ifdef DEBIAN_NEEDS_TO_UPDATE_THEIR_OPENAL + alGetSourceiv(gSourceID[src_headlandsound], AL_SOURCE_STATE, &tempint); +#else + alGetSourcei(gSourceID[src_headlandsound], AL_SOURCE_STATE, &tempint); +#endif + + if (tempint != AL_PLAYING){ + alSourcei(gSourceID[src_headlandsound], AL_BUFFER, gSampleSet[headlandsound]); + alSourcef(gSourceID[src_headlandsound], AL_MIN_GAIN, ALfloat(findLengthfast(avgvelocity)*2/findDistancefast(joints[i].position,camera.position)*soundscalefactor*2)); + alSourcef(gSourceID[src_headlandsound], AL_MAX_GAIN, ALfloat(findLengthfast(avgvelocity)*2/findDistancefast(joints[i].position,camera.position)*soundscalefactor*2)); + alSourcefv(gSourceID[src_headlandsound], AL_POSITION, gLoc); + alSourcePlay(gSourceID[src_headlandsound]);} +*/ + + // I don't think above is needed... We'll see? + + if (m_headland) + { + m_headland = true; + SoundFX::inst()->playFX(gSampleSet[headlandsound], gLoc, + (findLengthfast(avgvelocity)*2/findDistancefast(joints[i].position,camera.position)*soundscalefactor*2), + (findLengthfast(avgvelocity)*2/findDistancefast(joints[i].position,camera.position)*soundscalefactor*2)); + } + + } + else if(joints[i].label==head) + { + m_headland = false; + } + + avgvelocity=0; + for(k=0; k2||findLengthfast(avgvelocity)>2)){ + avgvelocity+=joints[i].velocity; + gLoc[0]=joints[i].position.x/soundscalefactor; + gLoc[1]=joints[i].position.y/soundscalefactor; + gLoc[2]=joints[i].position.z/soundscalefactor; + + +/* +#ifdef DEBIAN_NEEDS_TO_UPDATE_THEIR_OPENAL + alGetSourceiv(gSourceID[src_bodylandsound], AL_SOURCE_STATE, &tempint); +#else + alGetSourcei(gSourceID[src_bodylandsound], AL_SOURCE_STATE, &tempint); +#endif + if (tempint != AL_PLAYING){ + alSourcei(gSourceID[src_bodylandsound], AL_BUFFER, gSampleSet[bodylandsound]); + alSourcef(gSourceID[src_bodylandsound], AL_MIN_GAIN, ALfloat(findLengthfast(joints[i].velocity)*1/findDistancefast(joints[i].position,camera.position)*soundscalefactor*2)); + alSourcef(gSourceID[src_bodylandsound], AL_MAX_GAIN, ALfloat(findLengthfast(joints[i].velocity)*1/findDistancefast(joints[i].position,camera.position)*soundscalefactor*2)); + alSourcefv(gSourceID[src_bodylandsound], AL_POSITION, gLoc); + alSourcePlay(gSourceID[src_bodylandsound]);} +*/ + + // I don't think above is needed... We'll see? + + if (!m_bodyland) + { + m_bodyland = true; + SoundFX::inst()->playFX(gSampleSet[bodylandsound], gLoc, + (findLengthfast(joints[i].velocity)*1/findDistancefast(joints[i].position,camera.position)*soundscalefactor*2), + (findLengthfast(joints[i].velocity)*1/findDistancefast(joints[i].position,camera.position)*soundscalefactor*2)); + } + + } + else if(joints[i].label==abdomen) + { + m_bodyland = false; + } + + } + }} + } + if(num_muscles) + for(int i=0; iblurred); + glVertex3f(joints[i].parent->position.x,joints[i].parent->position.y,joints[i].parent->position.z); + glColor4f(jointcolor[0],jointcolor[1],jointcolor[2],jointcolor[3]/joints[i].parent->blurred); + glVertex3f(joints[i].parent->oldposition.x,joints[i].parent->oldposition.y,joints[i].parent->oldposition.z); + glColor4f(jointcolor[0],jointcolor[1],jointcolor[2],jointcolor[3]/joints[i].blurred); + glVertex3f(joints[i].oldposition.x,joints[i].oldposition.y,joints[i].oldposition.z); + } + } + for(i=0; iblurred); + glVertex3f(muscles[i].parent1->position.x,muscles[i].parent1->position.y,muscles[i].parent1->position.z); + glColor4f(jointcolor[0],jointcolor[1],jointcolor[2],jointcolor[3]/muscles[i].parent2->blurred); + glVertex3f(muscles[i].parent2->position.x,muscles[i].parent2->position.y,muscles[i].parent2->position.z); + glColor4f(jointcolor[0],jointcolor[1],jointcolor[2],jointcolor[3]/muscles[i].parent2->blurred); + glVertex3f(muscles[i].parent2->oldposition.x,muscles[i].parent2->oldposition.y,muscles[i].parent2->oldposition.z); + glColor4f(jointcolor[0],jointcolor[1],jointcolor[2],jointcolor[3]/muscles[i].parent1->blurred); + glVertex3f(muscles[i].parent1->oldposition.x,muscles[i].parent1->oldposition.y,muscles[i].parent1->oldposition.z); + } + } + glEnd(); + + glBegin(GL_LINES); + for(i=0; iblurred); + glVertex3f(joints[i].parent->position.x,joints[i].parent->position.y,joints[i].parent->position.z); + } + } + for(i=0; iblurred); + glVertex3f(muscles[i].parent1->position.x,muscles[i].parent1->position.y,muscles[i].parent1->position.z); + glColor4f(jointcolor[0],jointcolor[1],jointcolor[2],jointcolor[3]/muscles[i].parent2->blurred); + glVertex3f(muscles[i].parent2->position.x,muscles[i].parent2->position.y,muscles[i].parent2->position.z); + } + } + glColor3f(.6f,.6f,0); + if(muscleview==1) + for(int i=0; iposition.x,muscles[i].parent1->position.y,muscles[i].parent1->position.z); + glVertex3f(muscles[i].parent2->position.x,muscles[i].parent2->position.y,muscles[i].parent2->position.z); + } + } + glEnd(); + + if(muscleview!=2){ + glPointSize(3); + glBegin(GL_POINTS); + for(int i=0; i=num_joints||which<0)joints[num_joints].hasparent=0; + if(which=0){ + joints[num_joints].parent=&joints[which]; + joints[num_joints].hasparent=1; + joints[num_joints].length=findDistance(joints[num_joints].position,joints[num_joints].parent->position); + } + num_joints++; + } +} + +void Skeleton::DeleteJoint(int whichjoint) +{ + if(whichjoint=0){ + for(int i=0;i=num_joints||which<0)joints[whichjoint].hasparent=0; + if(which=0){ + joints[whichjoint].parent=&joints[which]; + joints[whichjoint].hasparent=1; + joints[whichjoint].length=findDistance(joints[whichjoint].position,joints[whichjoint].parent->position); + } + } +} + +void Skeleton::AddMuscle(int attach1,int attach2,float minlength,float maxlength,int type) +{ + if(num_muscles=0 && attach2=0 && attach1!=attach2){ + muscles[num_muscles].parent1=&joints[attach1]; + muscles[num_muscles].parent2=&joints[attach2]; + muscles[num_muscles].length=findDistance(muscles[num_muscles].parent1->position,muscles[num_muscles].parent2->position); + muscles[num_muscles].targetlength=findDistance(muscles[num_muscles].parent1->position,muscles[num_muscles].parent2->position); + muscles[num_muscles].strength=.7f; + muscles[num_muscles].type=type; + muscles[num_muscles].minlength=minlength; + muscles[num_muscles].maxlength=maxlength; + + num_muscles++; + } +} + +void Skeleton::MusclesSet() +{ + for(int i=0;iposition,muscles[i].parent2->position); + } +} + +void Skeleton::FindRotationJoint(int which) +{ + XYZ temppoint1,temppoint2,tempforward; + float distance; + + temppoint1=joints[which].position; + temppoint2=joints[which].parent->position; + distance=findDistance(temppoint1,temppoint2); + joints[which].rotate2=asin((temppoint1.y-temppoint2.y)/distance)*rad2deg; + temppoint1.y=0; + temppoint2.y=0; + joints[which].rotate1=acos((temppoint1.z-temppoint2.z)/findDistance(temppoint1,temppoint2))*rad2deg; + if(temppoint1.x>temppoint2.x)joints[which].rotate1=360-joints[which].rotate1; + if(joints[which].label==head)tempforward=specialforward[0]; + else if(joints[which].label==rightshoulder||joints[which].label==rightelbow||joints[which].label==rightwrist||joints[which].label==righthand)tempforward=specialforward[1]; + else if(joints[which].label==leftshoulder||joints[which].label==leftelbow||joints[which].label==leftwrist||joints[which].label==lefthand)tempforward=specialforward[2]; + else if(joints[which].label==righthip||joints[which].label==rightknee||joints[which].label==rightankle)tempforward=specialforward[3]; + else if(joints[which].label==lefthip||joints[which].label==leftknee||joints[which].label==leftankle)tempforward=specialforward[4]; + else if(!joints[which].lower)tempforward=forward; + else if(joints[which].lower)tempforward=lowforward; + tempforward=DoRotation(tempforward,0,joints[which].rotate1-90,0); + tempforward=DoRotation(tempforward,0,0,joints[which].rotate2-90); + tempforward.y=0; + Normalise(&tempforward); + joints[which].rotate3=acos(0-tempforward.z)*rad2deg; + if(0>tempforward.x)joints[which].rotate3=360-joints[which].rotate3; +} + +void Skeleton::FindRotationMuscle(int which) +{ + XYZ temppoint1,temppoint2,tempforward; + float distance; + + temppoint1=muscles[which].parent1->position; + temppoint2=muscles[which].parent2->position; + distance=findDistance(temppoint1,temppoint2); + muscles[which].rotate2=asin((temppoint1.y-temppoint2.y)/distance)*rad2deg; + temppoint1.y=0; + temppoint2.y=0; + muscles[which].rotate1=acos((temppoint1.z-temppoint2.z)/findDistance(temppoint1,temppoint2)); + muscles[which].rotate1*=360/6.28f; + if(temppoint1.x>temppoint2.x)muscles[which].rotate1=360-muscles[which].rotate1; + if(muscles[which].parent1->label==head)tempforward=specialforward[0]; + else if(muscles[which].parent1->label==rightshoulder||muscles[which].parent1->label==rightelbow||muscles[which].parent1->label==rightwrist)tempforward=specialforward[1]; + else if(muscles[which].parent1->label==leftshoulder||muscles[which].parent1->label==leftelbow||muscles[which].parent1->label==leftwrist)tempforward=specialforward[2]; + else if(muscles[which].parent1->label==righthip||muscles[which].parent1->label==rightknee||muscles[which].parent1->label==rightankle)tempforward=specialforward[3]; + else if(muscles[which].parent1->label==lefthip||muscles[which].parent1->label==leftknee||muscles[which].parent1->label==leftankle)tempforward=specialforward[4]; + else if(!muscles[which].parent1->lower)tempforward=forward; + else if(muscles[which].parent1->lower)tempforward=lowforward; + tempforward=DoRotation(tempforward,0,muscles[which].rotate1-90,0); + tempforward=DoRotation(tempforward,0,0,muscles[which].rotate2-90); + tempforward.y=0; + Normalise(&tempforward); + muscles[which].rotate3=acos(0-tempforward.z)*rad2deg; + for(int i=0;itempforward.x)muscles[which].rotate3=360-muscles[which].rotate3; +} + +extern Skeleton testskeleton; + +void Animation::Load(char *fileName) +{ +// float placeholder[3]; + files.OpenFile((unsigned char*)fileName); + if(files.sFile){ + ReadInt(files.sFile, 1, &numframes); + for(int i=0;imrotate3[i][j-1]+180)mrotate3[i][j]-=360; + if(j!=0&&mrotate3[i][j]mrotate2[i][j-1]+180)mrotate2[i][j]-=360; + if(j!=0&&mrotate2[i][j]mrotate1[i][j-1]+180)mrotate1[i][j]-=360; + if(j!=0&&mrotate1[i][j]rotate3[i][j-1]+180)rotate3[i][j]-=360; + if(j!=0&&rotate3[i][j]rotate2[i][j-1]+180)rotate2[i][j]-=360; + if(j!=0&&rotate2[i][j]rotate1[i][j-1]+180)rotate1[i][j]-=360; + if(j!=0&&rotate1[i][j]mrotate3[i][j-1]+180)mrotate3[i][j]-=360; + if(j!=0&&mrotate3[i][j]mrotate2[i][j-1]+180)mrotate2[i][j]-=360; + if(j!=0&&mrotate2[i][j]mrotate1[i][j-1]+180)mrotate1[i][j]-=360; + if(j!=0&&mrotate1[i][j]mrotate3[i][numframes-1]+180)mrotate3[i][j]-=360; + if(j==0&&mrotate3[i][j]mrotate2[i][numframes-1]+180)mrotate2[i][j]-=360; + if(j==0&&mrotate2[i][j]mrotate1[i][numframes-1]+180)mrotate1[i][j]-=360; + if(j==0&&mrotate1[i][j]rotate3[i][j-1]+180)rotate3[i][j]-=360; + if(j!=0&&rotate3[i][j]rotate2[i][j-1]+180)rotate2[i][j]-=360; + if(j!=0&&rotate2[i][j]rotate1[i][j-1]+180)rotate1[i][j]-=360; + if(j!=0&&rotate1[i][j]rotate3[i][numframes-1]+180)rotate3[i][j]-=360; + if(j==0&&rotate3[i][j]rotate2[i][numframes-1]+180)rotate2[i][j]-=360; + if(j==0&&rotate2[i][j]rotate1[i][numframes-1]+180)rotate1[i][j]-=360; + if(j==0&&rotate1[i][j]mrotate3[i][j-1]+180)mrotate3[i][j]-=360; + if(j!=0&&mrotate3[i][j]mrotate2[i][j-1]+180)mrotate2[i][j]-=360; + if(j!=0&&mrotate2[i][j]mrotate1[i][j-1]+180)mrotate1[i][j]-=360; + if(j!=0&&mrotate1[i][j]rotate3[i][j-1]+180)rotate3[i][j]-=360; + if(j!=0&&rotate3[i][j]rotate2[i][j-1]+180)rotate2[i][j]-=360; + if(j!=0&&rotate2[i][j]rotate1[i][j-1]+180)rotate1[i][j]-=360; + if(j!=0&&rotate1[i][j]mrotate3[i][j-1]+180)mrotate3[i][j]-=360; + if(j!=0&&mrotate3[i][j]mrotate2[i][j-1]+180)mrotate2[i][j]-=360; + if(j!=0&&mrotate2[i][j]mrotate1[i][j-1]+180)mrotate1[i][j]-=360; + if(j!=0&&mrotate1[i][j]mrotate3[i][numframes-1]+180)mrotate3[i][j]-=360; + if(j==0&&mrotate3[i][j]mrotate2[i][numframes-1]+180)mrotate2[i][j]-=360; + if(j==0&&mrotate2[i][j]mrotate1[i][numframes-1]+180)mrotate1[i][j]-=360; + if(j==0&&mrotate1[i][j]rotate3[i][j-1]+180)rotate3[i][j]-=360; + if(j!=0&&rotate3[i][j]rotate2[i][j-1]+180)rotate2[i][j]-=360; + if(j!=0&&rotate2[i][j]rotate1[i][j-1]+180)rotate1[i][j]-=360; + if(j!=0&&rotate1[i][j]rotate3[i][numframes-1]+180)rotate3[i][j]-=360; + if(j==0&&rotate3[i][j]rotate2[i][numframes-1]+180)rotate2[i][j]-=360; + if(j==0&&rotate2[i][j]rotate1[i][numframes-1]+180)rotate1[i][j]-=360; + if(j==0&&rotate1[i][j] HEADER FILES <**/ +#ifdef WIN32 +#include +#endif + +#ifdef OS9 +#include +#include "alut.h" +#else +#include + #ifdef WIN32 + #include + #include + #else + #include + #include + #endif +#endif +#include "Quaternions.h" +#include "Constants.h" +#include "Files.h" +#include "Models.h" +#include "Camera.h" + +#define boneconnect 0 +#define constraint 1 +#define muscle 2 + +//head, neck, left shoulder, left elbow, left wrist, left hand + //right shoulder, right elbow, right wrist, right hand, + //middle, left hip, right hip,groin + //left knee,left ankle, left foot, right knee, right ankle, right foort + +#define head 1 +#define neck 2 +#define leftshoulder 3 +#define leftelbow 4 +#define leftwrist 5 +#define lefthand 6 +#define rightshoulder 7 +#define rightelbow 8 +#define rightwrist 9 +#define righthand 10 +#define abdomen 11 +#define lefthip 12 +#define righthip 13 +#define groin 14 +#define leftknee 15 +#define leftankle 16 +#define leftfoot 17 +#define rightknee 18 +#define rightankle 19 +#define rightfoot 20 + +class Joint +{ + public: + XYZ position; + XYZ oldposition; + XYZ realoldposition; + XYZ velocity; + XYZ offset; + float blurred; + float length; + float mass; + bool lower; + bool hasparent; + bool locked; + int modelnum; + bool visible; + bool existing; + Joint* parent; + int label; + int hasgun; + float rotate1,rotate2,rotate3; + + void DoConstraint(); +}; + +class Muscle +{ + public: + float length; + float targetlength; + Joint* parent1; + Joint* parent2; + float maxlength; + float minlength; + int type; + bool visible; + void DoConstraint(int broken); + float rotate1,rotate2,rotate3; + + float strength; +}; + +class Animation +{ + public: + Files files; + int numframes; + bool canbeoverridden; + bool ismodified[max_joints][max_frames]; + XYZ position[max_joints][max_frames]; + float twist[max_joints][max_frames]; + float twist2[max_joints][max_frames]; + float speed[max_frames]; + float gunrotation[max_frames]; + bool onground[max_joints][max_frames]; + XYZ forward[max_frames]; + float rotate1[max_joints][max_frames],rotate2[max_joints][max_frames],rotate3[max_joints][max_frames]; + float mrotate1[max_joints][max_frames],mrotate2[max_joints][max_frames],mrotate3[max_joints][max_frames]; + void Load(char *fileName); + void Load(char *fileName,float rotate); +}; + + +class Skeleton +{ + public: + + Skeleton(); + + int num_joints; + Joint joints[max_joints]; + int jointlabels[max_joints]; + + int num_muscles; + Muscle muscles[max_muscles]; + + int selected; + + int forwardjoints[3]; + XYZ forward; + + int lowforwardjoints[3]; + XYZ lowforward; + + int broken; + bool offsetted; + + XYZ specialforward[5]; + + int free; + + Files files; + + void DoConstraints(); + void DoConstraints(Model *collide, XYZ *move, float rotation); + void DoGravity(); + void DoBalance(); + void MusclesSet(); + void Draw(int muscleview); + void AddJoint(float x, float y, float z, int which); + void SetJoint(float x, float y, float z, int which, int whichjoint); + void DeleteJoint(int whichjoint); + void AddMuscle(int attach1,int attach2,float maxlength,float minlength,int type); + void DeleteMuscle(int whichmuscle); + void FindRotationJoint(int which); + void FindRotationMuscle(int which); + void Load(char *fileName); + + private: + // sound-specific for limiting to one shot at a time. + bool m_bodyland; + bool m_headland; +}; + +#endif + diff --git a/blackshades_revenge/Source/SoundFX.cpp b/blackshades_revenge/Source/SoundFX.cpp new file mode 100644 index 0000000..31da637 --- /dev/null +++ b/blackshades_revenge/Source/SoundFX.cpp @@ -0,0 +1,3 @@ +#include "SoundFX.h" + +SoundFX *SoundFX::m_singleton = NULL; \ No newline at end of file diff --git a/blackshades_revenge/Source/SoundFX.h b/blackshades_revenge/Source/SoundFX.h new file mode 100644 index 0000000..37733af --- /dev/null +++ b/blackshades_revenge/Source/SoundFX.h @@ -0,0 +1,239 @@ +#ifndef __BLACKSHADES_SOUNDFX_H +#define __BLACKSHADES_SOUNDFX_H + +#include +#include + +#ifdef OS9 +#include "alut.h" +#else + #ifdef WIN32 + #include + #include + #else + #include + #include + #endif +#endif + + +#define DEDICATED_SOURCES 3 + +class SoundFX +{ +private: + typedef std::vector source_list; + source_list m_sources; + + ALuint m_music_source; + ALuint m_enviro_source; + ALuint m_vision_source; + + static SoundFX *m_singleton; + +protected: + SoundFX() + { + ALuint sources[32]; + unsigned long total_sources = 32; + + ALint error = AL_NO_ERROR + 1; + + while ((error != AL_NO_ERROR) && total_sources > DEDICATED_SOURCES) + { + // crappy test implementation coming on + alGenSources(total_sources, sources); + + if ((error = alGetError()) == AL_NO_ERROR) + { + // push the sources array into the sources vector + std::insert_iterator ii(m_sources, m_sources.begin()); + + m_music_source = sources[0]; + m_enviro_source = sources[1]; + m_vision_source = sources[2]; + + // jump one ahead to skip the music source + std::copy(sources + DEDICATED_SOURCES, sources + total_sources, ii); + } + else + { + total_sources -= 2; + } + } + + } + + ~SoundFX() + { + for (source_list::iterator i = m_sources.begin(); i != m_sources.end(); ++i) + { + alDeleteSources(1, &(*i)); + } + + alDeleteSources(1, &m_music_source); + alDeleteSources(1, &m_enviro_source); + alDeleteSources(1, &m_vision_source); + } + +public: + + static SoundFX *inst() + { + if (m_singleton != NULL) + { + return m_singleton; + } + else + { + m_singleton = new SoundFX; + return m_singleton; + } + } + + static void clean() + { + delete m_singleton; + m_singleton = NULL; + } + +// NOTE! that psychic sound will probably need a dedicated channel ... pllgphfhfh1!!!! + + // reserved channel for music + ALuint getMusicSource(ALuint buffer = 0xFFFFFFFF) + { + + // possibly bad + float gLoc[] = {0.0f, 0.0f, 0.0f}; + + alSourcefv(m_music_source, AL_POSITION, gLoc); + alSourcei(m_music_source, AL_LOOPING, 1); + alSourcef(m_music_source, AL_MIN_GAIN, 0); + + if (buffer != 0xFFFFFFFF) + { + alSourceStop(m_music_source); + + alSourcei(m_music_source, AL_BUFFER, buffer); + } + + return m_music_source; + } + + ALuint getVisionSource(ALuint buffer = 0xFFFFFFFF) + { + + // possibly bad + float gLoc[] = {0.0f, 0.0f, 0.0f}; + + alSourcefv(m_vision_source, AL_POSITION, gLoc); + alSourcei(m_vision_source, AL_LOOPING, 1); + alSourcef(m_vision_source, AL_MIN_GAIN, 1); + + if (buffer != 0xFFFFFFFF) + { + alSourceStop(m_vision_source); + + alSourcei(m_vision_source, AL_BUFFER, buffer); + } + + return m_vision_source; + } + + + // reserved channel for rain, etc + ALuint getEnviroSource(ALuint buffer = 0xFFFFFFFF) + { + // possibly bad + float gLoc[] = {0.0f, 0.0f, 0.0f}; + + alSourcefv(m_enviro_source, AL_POSITION, gLoc); + alSourcei(m_enviro_source, AL_LOOPING, 1); + alSourcef(m_enviro_source, AL_MIN_GAIN, 0); + + if (buffer != 0xFFFFFFFF) + { + alSourceStop(m_enviro_source); + + alSourcei(m_enviro_source, AL_PITCH, 1); + alSourcei(m_enviro_source, AL_BUFFER, buffer); + } + + return m_enviro_source; + } + + ALuint getFreeSource(ALuint buffer, ALfloat min_gain = 0.0f, ALfloat max_gain = 1.0f) + { + source_list::iterator i = m_sources.begin(); + // skip dedicated sources + std::advance(i, (rand()%(m_sources.size() - DEDICATED_SOURCES)) + DEDICATED_SOURCES); + + // random pick, not optimal, but probably suitable. + ALuint pick = *i; + + i = m_sources.begin(); + // skip dedicated sources + std::advance(i, DEDICATED_SOURCES); + + for (; i != m_sources.end(); ++i) + { + if (!isPlaying(*i)) + { + pick = *i; + break; + } + } + + alSourceStop(pick); + + // possibly bad + float gLoc[] = {0.0f, 0.0f, 0.0f}; + + alSourcefv(pick, AL_POSITION, gLoc); + alSourcei(pick, AL_LOOPING, 0); + alSourcef(pick, AL_MIN_GAIN, min_gain); + alSourcef(pick, AL_MAX_GAIN, max_gain); + + alSourcei(pick, AL_BUFFER, buffer); + + return pick; + } + + void playFX(ALuint buffer, float *gloc = NULL, ALfloat min_gain = 0.0f, ALfloat max_gain = 1.0f, bool only_one = false) + { + if (only_one) + stopBuffer(buffer); + + ALuint snd = getFreeSource(buffer, min_gain, max_gain); + if (gloc != NULL) + alSourcefv(snd, AL_POSITION, gloc); + alSourcePlay(snd); + } + +private: + + void stopBuffer(ALuint buffer) + { + ALint state; + + for (source_list::iterator i = m_sources.begin(); i != m_sources.end(); ++i) + { + alGetSourcei(*i, AL_BUFFER, &state); + if (buffer == state) + { + alSourceStop(*i); + } + } + } + + bool isPlaying(ALuint source) + { + ALint state; + alGetSourcei(source, AL_SOURCE_STATE, &state); + return (AL_PLAYING == state)?true:false; + } +}; + + + +#endif \ No newline at end of file diff --git a/blackshades_revenge/Source/Sprites.cpp b/blackshades_revenge/Source/Sprites.cpp new file mode 100644 index 0000000..586a166 --- /dev/null +++ b/blackshades_revenge/Source/Sprites.cpp @@ -0,0 +1,505 @@ +#include "Sprites.h" + +extern double multiplier; +extern bool slomo; +extern Fog fog; +extern bool blood; +extern float fogcolorr; +extern float fogcolorg; +extern float fogcolorb; +//Functions +extern float sinefluct; +extern int environment; +extern Model gunmodels[10]; +extern Camera camera; +extern float precipitationhorz; +extern float precipitationvert; +extern float precipitationdensity; +extern float snowdelay; + +int Sprites::MakeSprite(int atype, float abrightness, float acolor1, float acolor2, float acolor3, XYZ alocation, XYZ avelocity, float asize){ + type[howmanysprites]=atype; + rotation[howmanysprites]=Random()%360; + brightness[howmanysprites]=abrightness; + color1[howmanysprites]=acolor1; + color2[howmanysprites]=acolor2; + color3[howmanysprites]=acolor3; + location[howmanysprites]=alocation; + oldlocation[howmanysprites]=alocation; + velocity[howmanysprites]=avelocity; + size[howmanysprites]=asize; + initialsize[howmanysprites]=asize; + initialbrightness[howmanysprites]=abrightness; + initialvelocity[howmanysprites]=avelocity; + alivetime[howmanysprites]=0; + owner[howmanysprites]=0; + if(howmanysprites=0){ + location[which]=location[howmanysprites-1]; + oldlocation[which]=oldlocation[howmanysprites-1]; + velocity[which]=velocity[howmanysprites-1]; + initialsize[which]=initialsize[howmanysprites-1]; + size[which]=size[howmanysprites-1]; + brightness[which]=brightness[howmanysprites-1]; + initialbrightness[which]=initialbrightness[howmanysprites-1]; + color1[which]=color1[howmanysprites-1]; + color2[which]=color2[howmanysprites-1]; + color3[which]=color3[howmanysprites-1]; + alivetime[which]=alivetime[howmanysprites-1]; + rotation[which]=rotation[howmanysprites-1]; + type[which]=type[howmanysprites-1]; + type[howmanysprites-1]=0; + + if(howmanysprites>0){howmanysprites--;} + } + + return 0; +} + +void Sprites::LoadFlareTexture(char *fileName) +{ + TGAImageRec *tempTexture; + GLuint type; + + //Load Image + tempTexture = LoadTGA( fileName ); + //Is it valid? + if(tempTexture){ + //Alpha channel? + if ( tempTexture->bpp == 24 ) + type = GL_RGB; + else + type = GL_RGBA; + + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + + glGenTextures( 1, &flaretextureptr ); + glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + + glBindTexture( GL_TEXTURE_2D, flaretextureptr); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + + gluBuild2DMipmaps( GL_TEXTURE_2D, type, tempTexture->sizeX, tempTexture->sizeY, type, GL_UNSIGNED_BYTE, tempTexture->data ); + free( tempTexture->data ); + free( tempTexture ); + } +} + +void Sprites::LoadMuzzleFlareTexture(char *fileName) +{ + TGAImageRec *tempTexture; + GLuint type; + + //Load Image + tempTexture = LoadTGA( fileName ); + //Is it valid? + if(tempTexture){ + //Alpha channel? + if ( tempTexture->bpp == 24 ) + type = GL_RGB; + else + type = GL_RGBA; + + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + + glGenTextures( 1, &muzzleflaretextureptr ); + glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + + glBindTexture( GL_TEXTURE_2D, muzzleflaretextureptr); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + + gluBuild2DMipmaps( GL_TEXTURE_2D, type, tempTexture->sizeX, tempTexture->sizeY, type, GL_UNSIGNED_BYTE, tempTexture->data ); + free( tempTexture->data ); + free( tempTexture ); + } +} + +void Sprites::LoadSmokeTexture(char *fileName) +{ + TGAImageRec *tempTexture; + GLuint type; + + //Load Image + tempTexture = LoadTGA( fileName ); + //Is it valid? + if(tempTexture){ + //Alpha channel? + if ( tempTexture->bpp == 24 ) + type = GL_RGB; + else + type = GL_RGBA; + + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + + glGenTextures( 1, &smoketextureptr ); + glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + + glBindTexture( GL_TEXTURE_2D, smoketextureptr); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + + gluBuild2DMipmaps( GL_TEXTURE_2D, type, tempTexture->sizeX, tempTexture->sizeY, type, GL_UNSIGNED_BYTE, tempTexture->data ); + free( tempTexture->data ); + free( tempTexture ); + } +} + +void Sprites::LoadBloodTexture(char *fileName) +{ + TGAImageRec *tempTexture; + GLuint type; + + //Load Image + tempTexture = LoadTGA( fileName ); + //Is it valid? + if(tempTexture){ + //Alpha channel? + if ( tempTexture->bpp == 24 ) + type = GL_RGB; + else + type = GL_RGBA; + + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + + glGenTextures( 1, &bloodtextureptr ); + glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + + glBindTexture( GL_TEXTURE_2D, bloodtextureptr); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + + gluBuild2DMipmaps( GL_TEXTURE_2D, type, tempTexture->sizeX, tempTexture->sizeY, type, GL_UNSIGNED_BYTE, tempTexture->data ); + free( tempTexture->data ); + free( tempTexture ); + } +} + +void Sprites::LoadRainTexture(char *fileName) +{ + TGAImageRec *tempTexture; + GLuint type; + + //Load Image + tempTexture = LoadTGA( fileName ); + //Is it valid? + if(tempTexture){ + //Alpha channel? + if ( tempTexture->bpp == 24 ) + type = GL_RGB; + else + type = GL_RGBA; + + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + + glGenTextures( 1, &raintextureptr ); + glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + + glBindTexture( GL_TEXTURE_2D, raintextureptr); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + + gluBuild2DMipmaps( GL_TEXTURE_2D, type, tempTexture->sizeX, tempTexture->sizeY, type, GL_UNSIGNED_BYTE, tempTexture->data ); + free( tempTexture->data ); + free( tempTexture ); + } +} + +void Sprites::LoadSnowTexture(char *fileName) +{ + TGAImageRec *tempTexture; + GLuint type; + + //Load Image + tempTexture = LoadTGA( fileName ); + //Is it valid? + if(tempTexture){ + //Alpha channel? + if ( tempTexture->bpp == 24 ) + type = GL_RGB; + else + type = GL_RGBA; + + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + + glGenTextures( 1, &snowtextureptr ); + glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + + glBindTexture( GL_TEXTURE_2D, snowtextureptr); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + + gluBuild2DMipmaps( GL_TEXTURE_2D, type, tempTexture->sizeX, tempTexture->sizeY, type, GL_UNSIGNED_BYTE, tempTexture->data ); + free( tempTexture->data ); + free( tempTexture ); + } +} + +void Sprites::LoadBulletTexture(char *fileName) +{ + TGAImageRec *tempTexture; + GLuint type; + + //Load Image + tempTexture = LoadTGA( fileName ); + //Is it valid? + if(tempTexture){ + //Alpha channel? + if ( tempTexture->bpp == 24 ) + type = GL_RGB; + else + type = GL_RGBA; + + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + + glGenTextures( 1, &bullettextureptr ); + glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + + glBindTexture( GL_TEXTURE_2D, bullettextureptr); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + + gluBuild2DMipmaps( GL_TEXTURE_2D, type, tempTexture->sizeX, tempTexture->sizeY, type, GL_UNSIGNED_BYTE, tempTexture->data ); + free( tempTexture->data ); + free( tempTexture ); + } +} + + +void Sprites::DoStuff() +{ + for(int i=0;i0){ + velocity[i].y+=gravity*multiplier; + rotation[i]+=multiplier*2; + } + } + if(type[i]==bloodspritedown||type[i]==particlesspritedown){ + velocity[i].y+=gravity*multiplier; + } + + if(type[i]!=bulletinstant&&type[i]!=bullet)location[i]=location[i]+velocity[i]*multiplier; + + alivetime[i]+=multiplier; + if(brightness[i]<=0)DeleteSprite(i); + if(type[i]==snowsprite&&(location[i].y<-.1||environment!=snowy_environment))DeleteSprite(i); + if(type[i]==rainsprite&&(location[i].y<-.1||environment!=rainy_environment))DeleteSprite(i); + + if(type[i]==snowsprite){ + if(location[i].xcamera.position.x+precipitationhorz){location[i].x-=precipitationhorz*2;} + if(location[i].z>camera.position.z+precipitationhorz){location[i].z-=precipitationhorz*2;} + if(location[i].y>camera.position.y+precipitationvert){location[i].y-=precipitationvert*2;} + } + if(type[i]==rainsprite){ + if(location[i].xcamera.position.x+precipitationhorz*.5){location[i].x-=precipitationhorz;} + if(location[i].z>camera.position.z+precipitationhorz*.5){location[i].z-=precipitationhorz;} + if(location[i].y>camera.position.y+precipitationvert){location[i].y-=precipitationvert*2;} + } + } +} + +void Sprites::draw() +{ + float M[16]; + XYZ begProj,endProj,avgProj,persp; + //XYZ between; + float oolen,dx,dy; + float bulletsize; + XYZ point; + glAlphaFunc(GL_GREATER, 0.01f); + + //glEnable(GL_POLYGON_OFFSET_FILL); + + glEnable(GL_BLEND); + glDisable(GL_CULL_FACE); + glEnable(GL_TEXTURE_2D); + glDisable(GL_LIGHTING); + glDepthMask(0); + glAlphaFunc(GL_GREATER, 0.01f); + for(int i=0;i +#endif + +#include "Quaternions.h" +#ifdef OS9 +#include +#include +#else +#include +#include +#endif +#include "Files.h" +#include "TGALoader.h" +#include "Quaternions.h" +#include "Camera.h" +#include "Models.h" +#include "Fog.h" +// +// Model Structures +// + +#define maxsprites 2000 + +#define muzzleflashsprite 1 +#define smokesprite 2 +#define smokespritenoup 3 +#define flashsprite 6 +#define grenadesprite 7 +#define pinsprite 8 +#define spoonsprite 9 +#define bloodspritedown 10 +#define bloodspritenoup 11 +#define particlesspritedown 12 +#define snowsprite 13 +#define rainsprite 14 + +#define bullet 4 +#define bulletinstant 5 + +class Sprites{ + public: + GLuint flaretextureptr; + GLuint muzzleflaretextureptr; + GLuint smoketextureptr; + GLuint bullettextureptr; + GLuint bloodtextureptr; + GLuint raintextureptr; + GLuint snowtextureptr; + + int howmanysprites; + + XYZ location[maxsprites]; + XYZ oldlocation[maxsprites]; + XYZ velocity[maxsprites]; + XYZ initialvelocity[maxsprites]; + float size[maxsprites]; + float initialsize[maxsprites]; + float brightness[maxsprites]; + float initialbrightness[maxsprites]; + float color1[maxsprites]; + float color2[maxsprites]; + float color3[maxsprites]; + float alivetime[maxsprites]; + float rotation[maxsprites]; + int type[maxsprites]; + int owner[maxsprites]; + + void draw(); + + int DeleteSprite(int which); + int MakeSprite(int atype, float abrightness, float acolor1, float acolor2, float acolor3, XYZ alocation, XYZ avelocity, float asize); + int MakeSprite(int atype, float abrightness, float acolor1, float acolor2, float acolor3, XYZ alocation, XYZ avelocity, float asize, int aowner); + + void DoStuff(); + void LoadMuzzleFlareTexture(char *fileName); + void LoadFlareTexture(char *fileName); + void LoadSmokeTexture(char *fileName); + void LoadBulletTexture(char *fileName); + void LoadBloodTexture(char *fileName); + void LoadSnowTexture(char *fileName); + void LoadRainTexture(char *fileName); + + ~Sprites() { + glDeleteTextures( 1, (const GLuint *)muzzleflaretextureptr ); + glDeleteTextures( 1, (const GLuint *)flaretextureptr ); + glDeleteTextures( 1, (const GLuint *)bullettextureptr ); + glDeleteTextures( 1, (const GLuint *)smoketextureptr ); + glDeleteTextures( 1, (const GLuint *)bloodtextureptr ); + glDeleteTextures( 1, (const GLuint *)raintextureptr ); + glDeleteTextures( 1, (const GLuint *)snowtextureptr ); + }; +}; + +#endif + diff --git a/blackshades_revenge/Source/Support.cpp b/blackshades_revenge/Source/Support.cpp new file mode 100644 index 0000000..05d60b4 --- /dev/null +++ b/blackshades_revenge/Source/Support.cpp @@ -0,0 +1,411 @@ +#include +#include +#ifdef __linux__ +#include +#include +#include +#include +#include +#endif + +#include "SDL.h" + +#include "Support.h" +#include "Files.h" + +int Random() +{ +#if RAND_MAX >= 65535 + return (rand() % 65535) - 32767; +#else + return (rand() % 32767) - 32767/2; +#endif +} + +void Microseconds(UnsignedWide *microTickCount) +{ + /* NOTE: hi isn't used in BS, so it's not implemented here */ + /* TODO: does game need microsecond precision? */ + microTickCount->hi = 0; + microTickCount->lo = SDL_GetTicks() * 1000; +} + +void GetMouse(Point *p) +{ + int x; + int y; + + SDL_GetMouseState(&x, &y); + + p->h = x; + p->v = y; +} + +void GetMouseRel(Point *p) +{ + int x; + int y; + + SDL_GetRelativeMouseState(&x, &y); + + p->h = x; + p->v = y; +} +int Button(void) +{ + return (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON(1)); +} + +void InitMouse() +{ +// STUB_FUNCTION; +} + +void MoveMouse(int xcoord, int ycoord, Point *mouseloc) +{ + /* TODO: mouse warp is annoying when we can just grab the mouse */ + SDL_WarpMouse(xcoord, ycoord); + SDL_PumpEvents(); + GetMouse(mouseloc); +} + +void DisposeMouse() +{ +// STUB_FUNCTION; +} + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#ifndef MAX_PATH +#define MAX_PATH 256 +#endif + +static int find_filename(char *filename) +{ + FILE *test = fopen(filename, "rb"); + if(test == NULL) + return 0; + + fclose(test); + return 1; + + // don't care + /* + char *ptr; + char *cur; + char *next; + DIR *dir; + struct dirent *dirent; + + if (access(filename, R_OK) == 0) { + return 1; + } + + ptr = filename; + + while (*ptr) { + if (ptr == filename || *ptr == '/') { + if (*ptr == '/') { + cur = ptr+1; + } else { + cur = ptr; + } + + if (*cur == 0) { + // hit the end + break; + } + + next = strchr(cur, '/'); + + if (ptr != filename) { + *ptr = 0; + } + + if (next) { + *next = 0; + } + + if (ptr == filename && *ptr == '/') { + dir = opendir("/"); + } else { + dir = opendir(filename); + } + + if (dir == NULL) { + if (ptr != filename) { + *ptr = '/'; + } + + if (next) { + *next = 0; + } + + return 0; + } + + while ((dirent = readdir(dir)) != NULL) { + if (strcasecmp(cur, dirent->d_name) == 0) { + strcpy(cur, dirent->d_name); + break; + } + } + + closedir(dir); + + if (ptr != filename) { + *ptr = '/'; + } + + if (next) { + *next = '/'; + ptr = next; + } else { + ptr++; + } + } else { + ptr++; + } + } + + if (access(filename, R_OK) == 0) { + return 1; + } + + return 0; + */ +} + +static void fix_filename(const char *original, char *fixed) +{ + const char *start; + int i; + int len; + + start = original; + if (original[0] == ':') { + start = &original[1]; + } + + fixed[MAX_PATH-1] = 0; + + strncpy(fixed, start, MAX_PATH); + + /* check to see if strncpy overwrote the terminator */ + if (fixed[MAX_PATH-1] != 0) { + fixed[MAX_PATH-1] = 0; + + fprintf(stderr, "ERROR: file truncation error: %s -> %s\n", + original, fixed); + } + + len = strlen(fixed); + for (i = 0; i < len; i++) { + if (fixed[i] == ':') { + fixed[i] = '/'; + } + } + + /* + here we would try to see if the file is available (game dir), + else try another dir + + really, this function also needs a flag to indicate whether + it should only go to local (write) or both (read) + */ + + if (find_filename(fixed) == 0) { + fprintf(stderr, "find failed: %s\n", fixed); + } +} + +/* +Convenient Filename Hacks +*/ + +FILE *cfh_fopen(const char *filename, const char *mode) +{ + char filename1[MAX_PATH]; + + fix_filename(filename, filename1); + + return fopen(filename1, mode); +} + +FILE *Files::OpenFile(Str255 Name) +{ + char filename1[MAX_PATH]; + + fix_filename((char *)Name, filename1); + + //sFile = open(filename1, O_RDONLY | O_BINARY); + sFile = fopen(filename1, "rb"); + + return sFile; +} + +void Files::EndLoad() +{ + if (sFile != NULL) { + FSClose( sFile ); + } + + //sFile = -1; + sFile = NULL; +} + +#ifdef NOOGG +/* + Our own special magic version that fixes the filename. + */ +void alutLoadWAVFile_CFH(char *filename, ALenum *format, void **wave, + unsigned int *size, ALsizei *freq) +{ + char filename1[MAX_PATH]; + ALsizei format1, size1, freq1; + //ALsizei bits1; + + fix_filename(filename, filename1); + +#ifdef __APPLE_ + //alutLoadWAVFile(filename1, wave, &format1, &size1, &bits1, &freq1); + alutLoadWAVFile(filename1,(int *)&format1,wave,&size1,&freq1); +#endif +#ifdef WIN32 + ALboolean loop; + alutLoadWAVFile(filename1,(int *)&format1,wave,&size1,&freq1,&loop); +#endif +#ifdef __linux__ + ALboolean loop; + alutLoadWAVFile((ALbyte *)filename1,(int *)&format1,wave,&size1,&freq1,&loop); +#endif + + *format = format1; + *size = size1; + *freq = freq1; +} + +void alutUnloadWAV_CFH(ALenum format, void *wave, unsigned int size, + ALsizei freq) +{ + free(wave); +} +#else +#include + +/* +Read the requested OGG file into memory, and extract the information required +by OpenAL +*/ +void LoadOGG_CFH(char *filename, ALenum *format, void **wave, + unsigned int *size, ALsizei *freq) +{ + char filename1[MAX_PATH]; + ALsizei format1, size1, freq1; + void *wave1; + OggVorbis_File vf; + vorbis_info *vi; + FILE *fp; + int current_section; + char *buf; + int asize; + int err; + int eof; + +#if BYTE_ORDER == BIG_ENDIAN + const int endian = 1; +#else + const int endian = 0; +#endif + + /* try to find the real file (and place it in filename1) */ + fix_filename(filename, filename1); + + /* open it for reading */ + fp = fopen(filename1, "rb"); + if (fp == NULL) { + fprintf(stderr, "ERROR: unable to open %s\n", filename1); + exit(EXIT_FAILURE); + } + + /* open it up */ + err = ov_open(fp, &vf, NULL, 0); + if (err < 0) { + fprintf(stderr, "ERROR: vorbis error %d opening %s\n", -err, filename1); + exit(EXIT_FAILURE); + } + + /* get the ogg information */ + vi = ov_info(&vf, -1); + if (vi == NULL) { + fprintf(stderr, "ERROR: vorbis error opening %s (ov_info failed)\n", filename1); + exit(EXIT_FAILURE); + } + + /* calculate the byte size */ + size1 = vi->channels * 2 * ov_pcm_total(&vf, -1); + + /* hack around some possible ogg vorbis weirdness */ + asize = ((size1 + 2047) / 2048 + 1) * 2048; + + /* allocate our buffer */ + wave1 = malloc(asize); + + if (wave1 == NULL) { + fprintf(stderr, "ERROR: could not allocate %d bytes while loading %s\n", size1, filename1); + exit(EXIT_FAILURE); + } + + /* read it in */ + eof = 0; + buf = (char *)wave1; + + while(!eof) { + long ret = ov_read(&vf, buf, 1024, endian, 2, 1, + ¤t_section); + + if (ret == 0) { + /* end of file */ + eof = 1; + } else if (ret < 0) { + /* some sort of error */ + + /* TODO: is this ok to ignore? */ + } else { + buf += ret; + } + } + + /* get the rest of the information */ + if (vi->channels == 1) { + format1 = AL_FORMAT_MONO16; + } else if (vi->channels == 2) { + format1 = AL_FORMAT_STEREO16; + } else { + fprintf(stderr, "ERROR: ogg %s has %d channels\n", filename1, vi->channels); + exit(EXIT_FAILURE); + } + + freq1 = vi->rate; + + /* we are done with the ogg, so free it */ + ov_clear(&vf); + + /* finall, give the values to the caller */ + *format = format1; + *size = size1; + *freq = freq1; + *wave = wave1; +} + +/* +Free the OGG buffer +*/ +void FreeOGG(ALenum format, void *wave, unsigned int size, + ALsizei freq) +{ + free(wave); +} +#endif diff --git a/blackshades_revenge/Source/Support.h b/blackshades_revenge/Source/Support.h new file mode 100644 index 0000000..2bc15a4 --- /dev/null +++ b/blackshades_revenge/Source/Support.h @@ -0,0 +1,80 @@ +#ifndef SUPPORT_H +#define SUPPORT_H + +#include + +#ifdef __linux__ +#include +#endif + +#ifdef WIN32 +#include +#include +#else +#include +#include +#endif + +#ifdef __linux__ +#define STUB_FUNCTION fprintf(stderr,"STUB: %s at " __FILE__ ", line %d, thread %d\n",__FUNCTION__,__LINE__,getpid()) +#else +#define STUB_FUNCTION fprintf(stderr,"STUB: " __FILE__ ", line %d\n",__LINE__) +#endif + +#define fsFromStart SEEK_SET + +typedef unsigned char * Str255; +typedef int OSErr; +typedef short int SInt16; + +typedef bool Boolean; +#ifdef __linux__ +#define TRUE true +#define FALSE false +#endif + + +typedef struct UnsignedWide +{ + unsigned int lo; + unsigned int hi; +} UnsignedWide; + +typedef struct Point +{ + int h; + int v; +} Point; + +#ifdef WIN32 +#define SetFPos(fildes, whence, offset) fseek(fildes, offset, whence) +#define FSClose(fildes) fclose(fildes) +#else +#define SetFPos(fildes, whence, offset) lseek(fildes, offset, whence) +#define FSClose(fildes) close(fildes) +#endif + +int Random(); +void Microseconds(UnsignedWide *microTickCount); +void GetMouse(Point *p); +void GetMouseRel(Point *p); +void GetKeys(unsigned long *keys); +int Button(void); +#ifdef NOOGG +void alutLoadWAVFile_CFH(char *filename, ALenum *format, void **wave, + unsigned int *size, ALsizei *freq); +void alutUnloadWAV_CFH(ALenum format, void *wave, unsigned int size, + ALsizei freq); +//#define alutLoadWAVFile alutLoadWAVFile_CFH +#define alutUnloadWAV alutUnloadWAV_CFH +#else +void LoadOGG_CFH(char *filename, ALenum *format, void **wave, + unsigned int *size, ALsizei *freq); +void FreeOGG(ALenum format, void *wave, unsigned int size, + ALsizei freq); +#endif + + +FILE *cfh_fopen(const char *filename, const char *mode); + +#endif diff --git a/blackshades_revenge/Source/TGALoader.cpp b/blackshades_revenge/Source/TGALoader.cpp new file mode 100644 index 0000000..53e4f24 --- /dev/null +++ b/blackshades_revenge/Source/TGALoader.cpp @@ -0,0 +1,87 @@ +/**> HEADER FILES <**/ +#ifdef WIN32 +#include "Support.h" +#endif + +#include "TGALoader.h" + + +/********************> LoadTGA() <*****/ +TGAImageRec* LoadTGA( char *filename ) +{ + GLubyte TGAheader[12]={0,0,2,0,0,0,0,0,0,0,0,0}; // Uncompressed TGA Header + GLubyte TGAcompare[12]; // Used To Compare TGA Header + GLubyte header[6]; // First 6 Useful Bytes From The Header + GLuint bytesPerPixel; // Holds Number Of Bytes Per Pixel Used In The TGA File + GLuint imageSize; // Used To Store The Image Size When Setting Aside Ram + GLuint temp; // Temporary Variable + GLuint type = GL_RGBA; // Set The Default GL Mode To RBGA (32 BPP) + TGAImageRec *texture; + FILE *file; + + // Open The TGA File + file = cfh_fopen( filename, "rb" ); + + if( ( file == NULL ) || // Does File Even Exist? + ( fread( TGAcompare, 1, sizeof( TGAcompare ), file ) != sizeof( TGAcompare ) ) || // Are There 12 Bytes To Read? + ( memcmp( TGAheader, TGAcompare, sizeof( TGAheader ) ) != 0 ) || // Does The Header Match What We Want? + ( fread( header, 1, sizeof( header ), file ) != sizeof( header ) ) )// If So Read Next 6 Header Bytes + { + // If anything failed then close the file and return false + fclose( file ); + return NULL; + } + + // Create a new RGBAImageRec + texture = ( TGAImageRec* )malloc( sizeof( TGAImageRec ) ); + + // Determine the TGA width (highbyte*256+lowbyte) and height (highbyte*256+lowbyte) + texture->sizeX = header[1] * 256 + header[0]; + texture->sizeY = header[3] * 256 + header[2]; + + // Make sure the height, width, and bit depth are valid + if( ( texture->sizeX <= 0 ) || ( texture->sizeY <= 0 ) || ( ( header[4] != 24 ) && ( header[4] != 32 ) ) ) + { + // If anything failed then close the file, free up memory for the image, and return NULL + fclose( file ); + free( texture ); + return NULL; + } + + // Grab The TGA's Bits Per Pixel (24 or 32) + texture->bpp = header[4]; + bytesPerPixel = texture->bpp/8; // Divide By 8 To Get The Bytes Per Pixel + + // Calculate The Memory Required For The TGA Data + imageSize = texture->sizeX * texture->sizeY * bytesPerPixel; + + // Reserve Memory To Hold The TGA Data + texture->data = ( GLubyte* )malloc( imageSize ); + + // Make sure the right amount of memory was allocated + if( ( texture->data == NULL ) || ( fread( texture->data, 1, imageSize, file ) != imageSize ) ) + { + // Free up the image data if there was any + if( texture->data != NULL ) + free( texture->data ); + + // If anything failed then close the file, free up memory for the image, and return NULL + fclose( file ); + free( texture ); + return NULL; + } + + // Loop Through The Image Data + for( GLuint i = 0; i < int( imageSize ); i += bytesPerPixel ) + { + // Swaps The 1st And 3rd Bytes ('R'ed and 'B'lue) + temp = texture->data[i]; // Temporarily Store The Value At Image Data 'i' + texture->data[i] = texture->data[i + 2]; // Set The 1st Byte To The Value Of The 3rd Byte + texture->data[i + 2] = temp; // Set The 3rd Byte To The Value In 'temp' (1st Byte Value) + } + + // Close The File + fclose( file ); + + return texture; +} diff --git a/blackshades_revenge/Source/TGALoader.h b/blackshades_revenge/Source/TGALoader.h new file mode 100644 index 0000000..5dd91ef --- /dev/null +++ b/blackshades_revenge/Source/TGALoader.h @@ -0,0 +1,38 @@ +#ifdef OS9 +#pragma once +#endif + +#ifndef _TGA_LOADER_H_ +#define _TGA_LOADER_H_ + + +/**> HEADER FILES <**/ +#ifdef WIN32 +#include +#endif + +#include +#include +#include +#ifdef OS9 +#include "gl.h" +#else +#include +#endif + +/**> DATA STRUCTURES <**/ +typedef struct TGAImageRec +{ + GLubyte *data; // Image Data (Up To 32 Bits) + GLuint bpp; // Image Color Depth In Bits Per Pixel. + GLuint sizeX; + GLuint sizeY; +} TGAImageRec; + + + +/**> FUNCTION PROTOTYPES <**/ +TGAImageRec* LoadTGA( char *filename ); + + +#endif diff --git a/blackshades_revenge/Source/Text.cpp b/blackshades_revenge/Source/Text.cpp new file mode 100644 index 0000000..2b64b4b --- /dev/null +++ b/blackshades_revenge/Source/Text.cpp @@ -0,0 +1,92 @@ +/**> HEADER FILES <**/ +#include "Text.h" + +void Text::LoadFontTexture(char *fileName) +{ + TGAImageRec *tempTexture; + GLuint type; + + //Load Image + tempTexture = LoadTGA( fileName ); + //Is it valid? + if(tempTexture){ + //Alpha channel? + if ( tempTexture->bpp == 24 ) + type = GL_RGB; + else + type = GL_RGBA; + + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + + glGenTextures( 1, &FontTexture ); + glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + + glBindTexture( GL_TEXTURE_2D, FontTexture); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + + gluBuild2DMipmaps( GL_TEXTURE_2D, type, tempTexture->sizeX, tempTexture->sizeY, type, GL_UNSIGNED_BYTE, tempTexture->data ); + free( tempTexture->data ); + free( tempTexture ); + } +} + +void Text::BuildFont() // Build Our Font Display List +{ + float cx; // Holds Our X Character Coord + float cy; // Holds Our Y Character Coord + int loop; + + base=glGenLists(256); // Creating 256 Display Lists + glBindTexture(GL_TEXTURE_2D, FontTexture); // Select Our Font Texture + for (loop=0; loop<256; loop++) // Loop Through All 256 Lists + { + cx=float(loop%16)/16.0f; // X Position Of Current Character + cy=float(loop/16)/16.0f; // Y Position Of Current Character + + glNewList(base+loop,GL_COMPILE); // Start Building A List + glBegin(GL_QUADS); // Use A Quad For Each Character + glTexCoord2f(cx,1-cy-0.0625f+.001); // Texture Coord (Bottom Left) + glVertex2i(0,0); // Vertex Coord (Bottom Left) + glTexCoord2f(cx+0.0625f,1-cy-0.0625f+.001); // Texture Coord (Bottom Right) + glVertex2i(16,0); // Vertex Coord (Bottom Right) + glTexCoord2f(cx+0.0625f,1-cy-.001); // Texture Coord (Top Right) + glVertex2i(16,16); // Vertex Coord (Top Right) + glTexCoord2f(cx,1-cy-+.001); // Texture Coord (Top Left) + glVertex2i(0,16); // Vertex Coord (Top Left) + glEnd(); // Done Building Our Quad (Character) + glTranslated(10,0,0); // Move To The Right Of The Character + glEndList(); // Done Building The Display List + } // Loop Until All 256 Are Built +} + +void Text::glPrint(GLint x, GLint y, char *string, int set, float size, float width, float height) // Where The Printing Happens +{ + if (set>1) + { + set=1; + } + glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + glBindTexture(GL_TEXTURE_2D, FontTexture); // Select Our Font Texture + glDisable(GL_DEPTH_TEST); // Disables Depth Testing + glDisable(GL_LIGHTING); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + glMatrixMode(GL_PROJECTION); // Select The Projection Matrix + glPushMatrix(); // Store The Projection Matrix + glLoadIdentity(); // Reset The Projection Matrix + glOrtho(0,width,0,height,-100,100); // Set Up An Ortho Screen + glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix + glPushMatrix(); // Store The Modelview Matrix + glLoadIdentity(); + glScalef(size,size,1); // Reset The Modelview Matrix + glTranslated(x,y,0); // Position The Text (0,0 - Bottom Left) + glListBase(base-32+(128*set)); // Choose The Font Set (0 or 1) + glCallLists(strlen(string),GL_BYTE,string); // Write The Text To The Screen + glMatrixMode(GL_PROJECTION); // Select The Projection Matrix + glPopMatrix(); // Restore The Old Projection Matrix + glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix + glPopMatrix(); // Restore The Old Projection Matrix + glEnable(GL_DEPTH_TEST); // Enables Depth Testing + glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); +} diff --git a/blackshades_revenge/Source/Text.h b/blackshades_revenge/Source/Text.h new file mode 100644 index 0000000..2ecccbb --- /dev/null +++ b/blackshades_revenge/Source/Text.h @@ -0,0 +1,37 @@ +#ifndef _TEXT_H_ +#define _TEXT_H_ + + +/**> HEADER FILES <**/ +#ifdef WIN32 +#include +#endif + +#include "Quaternions.h" +#ifdef OS9 +#include +#include +#else +#include +#include +#endif +#include "Files.h" +#include "Quaternions.h" +#include "TGALoader.h" + +class Text{ + public: + GLuint FontTexture; + GLuint base; + + void LoadFontTexture(char *fileName); + void BuildFont(); + void glPrint(GLint x, GLint y, char *string, int set, float size, float width, float height); + + ~Text(){ + glDeleteTextures( 1, (const GLuint *)FontTexture ); + } +}; + +#endif + diff --git a/blackshades_revenge/Source/Timer.cpp b/blackshades_revenge/Source/Timer.cpp new file mode 100644 index 0000000..f22d5e2 --- /dev/null +++ b/blackshades_revenge/Source/Timer.cpp @@ -0,0 +1,31 @@ +/**> HEADER FILES <**/ +#ifdef WIN32 +#include "Support.h" +#endif + +#include +#include "Timer.h" + + +/********************> Timer <*****/ +void TimerInit(timer* theTimer) +{ + UnsignedWide ms; + + Microseconds(&ms); + + memset(theTimer, 0, sizeof(timer)); + + theTimer->mm_timer_start = ms.lo; + theTimer->mm_timer_elapsed = theTimer->mm_timer_start; +} + +float TimerGetTime(timer* theTimer) +{ + UnsignedWide ms; + + Microseconds(&ms); + + + return( (float) (ms.lo - theTimer->mm_timer_start) * 1000.0f); +} diff --git a/blackshades_revenge/Source/Timer.h b/blackshades_revenge/Source/Timer.h new file mode 100644 index 0000000..c0c99a1 --- /dev/null +++ b/blackshades_revenge/Source/Timer.h @@ -0,0 +1,18 @@ +#ifndef _TIMER_H_ +#define _TIMER_H_ + + +/**> HEADER FILES <**/ +class timer +{ + public: + unsigned long mm_timer_start; + unsigned long mm_timer_elapsed; +}; + + +void TimerInit(timer* theTimer); +float TimerGetTime(timer* theTimer); + +#endif + diff --git a/blackshades_revenge/Source/macdefines.h b/blackshades_revenge/Source/macdefines.h new file mode 100644 index 0000000..1285028 --- /dev/null +++ b/blackshades_revenge/Source/macdefines.h @@ -0,0 +1,7 @@ +#ifndef __MACDEFINES_H +#define __MACDEFINES_H + +// this is not optimum, but it works +typedef char * Str255; + +#endif \ No newline at end of file diff --git a/blackshades_revenge/TODO b/blackshades_revenge/TODO new file mode 100644 index 0000000..dea061d --- /dev/null +++ b/blackshades_revenge/TODO @@ -0,0 +1,32 @@ + +Implement SDL_image for pngs +CLI Options +Keyboard config shit +toggling third person +AI Fix +What Ryan said about it: +"I don't have the source in front of me, but it looks like the people walk +correctly, but keep deciding to change their destination...this is likely +because we're reading the path model wrong or something. I don't know. +There's path determination code that if you comment it out, everyone +walks in a straight line, so that's the problem. Whether it's the +determination code itself or what it bases its calculation on...I have no +idea." + +What Toby did: +Something, I dunno, here's his explanation; + +"Staring deep into the barely commented depths of Black Shades, I tried +out Ryan's idea about the pathfinding that you put in the ToDo file. +Having acheived the everyone walking in straight lines effect, I set +about a bit of hackery. + +In GameTick.cpp, the variable realcheck is a trigger for a lot of the +pathfinding stuff. It checks whether we are at the end of our path, or +we are moving away from our target. I have no idea why the second bit +isn't working properly - maybe there is some funny updating going on for +either oldplayercoords or playercoords. Commenting out the second check +gets the game working with a more believable collection of moving people." + +And this was the patch: +http://cvs.icculus.org/horde/chora/diff.php/Source/GameTick.cpp?rt=blackshades&r1=1.7&r2=1.8&ty=h diff --git a/blackshades_revenge/blackshades.dsp b/blackshades_revenge/blackshades.dsp new file mode 100644 index 0000000..fdf0014 --- /dev/null +++ b/blackshades_revenge/blackshades.dsp @@ -0,0 +1,297 @@ +# Microsoft Developer Studio Project File - Name="blackshades" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=blackshades - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "blackshades.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "blackshades.mak" CFG="blackshades - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "blackshades - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "blackshades - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "blackshades - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "C:\Documents and Settings\BitlDev\Desktop\SDKs\OpenALSDK\Include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "BIG_ENDIAN" /D "FULLSCREEN" /D "NOOGG" /FR /YX /FD /c +# SUBTRACT CPP /X +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib opengl32.lib glu32.lib glaux.lib sdl.lib sdlmain.lib OpenAL32.lib ALut.lib SDL_image.lib /nologo /subsystem:windows /machine:I386 /out:"Release/blackshades_revenge.exe" /libpath:"C:\Documents and Settings\BitlDev\Desktop\SDKs\OpenALSDK\libs\\" +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "blackshades - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "C:\Documents and Settings\BitlDev\Desktop\SDKs\OpenALSDK\Include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "BIG_ENDIAN" /D "NOOGG" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib opengl32.lib glu32.lib glaux.lib sdl.lib sdlmain.lib OpenAL32.lib ALut.lib SDL_image.lib /nologo /subsystem:windows /debug /machine:I386 /out:"Debug/blackshades_revenge.exe" /pdbtype:sept /libpath:"C:\Documents and Settings\BitlDev\Desktop\SDKs\OpenALSDK\libs\\" + +!ENDIF + +# Begin Target + +# Name "blackshades - Win32 Release" +# Name "blackshades - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\blackshades.rc +# End Source File +# Begin Source File + +SOURCE=.\Source\Camera.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\Decals.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\Files.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\Fog.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\Frustum.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\GameDraw.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\GameInitDispose.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\GameLoop.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\GameTick.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\Globals.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\MacInput.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\Main.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\Maths.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\Models.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\Person.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\Quaternions.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\Serialize.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\Skeleton.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\SoundFX.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\Sprites.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\Support.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\Text.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\TGALoader.cpp +# End Source File +# Begin Source File + +SOURCE=.\Source\Timer.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\Source\Camera.h +# End Source File +# Begin Source File + +SOURCE=.\Source\Constants.h +# End Source File +# Begin Source File + +SOURCE=.\Source\Decals.h +# End Source File +# Begin Source File + +SOURCE=.\Source\Files.h +# End Source File +# Begin Source File + +SOURCE=.\Source\Fog.h +# End Source File +# Begin Source File + +SOURCE=.\Source\Frustum.h +# End Source File +# Begin Source File + +SOURCE=.\Source\Game.h +# End Source File +# Begin Source File + +SOURCE=.\Source\MacInput.h +# End Source File +# Begin Source File + +SOURCE=.\Source\Maths.h +# End Source File +# Begin Source File + +SOURCE=.\Source\Models.h +# End Source File +# Begin Source File + +SOURCE=.\Source\Person.h +# End Source File +# Begin Source File + +SOURCE=.\Source\PhysicsMath.h +# End Source File +# Begin Source File + +SOURCE=.\Source\Quaternions.h +# End Source File +# Begin Source File + +SOURCE=.\resource.h +# End Source File +# Begin Source File + +SOURCE=.\Source\Serialize.h +# End Source File +# Begin Source File + +SOURCE=.\Source\Skeleton.h +# End Source File +# Begin Source File + +SOURCE=.\Source\SoundFX.h +# End Source File +# Begin Source File + +SOURCE=.\Source\Sprites.h +# End Source File +# Begin Source File + +SOURCE=.\Source\Support.h +# End Source File +# Begin Source File + +SOURCE=.\Source\Text.h +# End Source File +# Begin Source File + +SOURCE=.\Source\TGALoader.h +# End Source File +# Begin Source File + +SOURCE=.\Source\Timer.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Source File + +SOURCE=.\notes.txt +# End Source File +# End Target +# End Project diff --git a/blackshades_revenge/blackshades.plg b/blackshades_revenge/blackshades.plg new file mode 100644 index 0000000..b461306 --- /dev/null +++ b/blackshades_revenge/blackshades.plg @@ -0,0 +1,48 @@ + + +
+

Build Log

+

+--------------------Configuration: blackshades - Win32 Release-------------------- +

+

Command Lines

+Creating temporary file "C:\DOCUME~1\BitlDev\LOCALS~1\Temp\RSP36.tmp" with contents +[ +kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib opengl32.lib glu32.lib glaux.lib sdl.lib sdlmain.lib OpenAL32.lib ALut.lib SDL_image.lib /nologo /subsystem:windows /incremental:no /pdb:"Release/blackshades_revenge.pdb" /machine:I386 /out:"Release/blackshades_revenge.exe" /libpath:"C:\Documents and Settings\BitlDev\Desktop\SDKs\OpenALSDK\libs\\" +".\Release\Camera.obj" +".\Release\Decals.obj" +".\Release\Files.obj" +".\Release\Fog.obj" +".\Release\Frustum.obj" +".\Release\GameDraw.obj" +".\Release\GameInitDispose.obj" +".\Release\GameLoop.obj" +".\Release\GameTick.obj" +".\Release\Globals.obj" +".\Release\MacInput.obj" +".\Release\Main.obj" +".\Release\Maths.obj" +".\Release\Models.obj" +".\Release\Person.obj" +".\Release\Quaternions.obj" +".\Release\Serialize.obj" +".\Release\Skeleton.obj" +".\Release\SoundFX.obj" +".\Release\Sprites.obj" +".\Release\Support.obj" +".\Release\Text.obj" +".\Release\TGALoader.obj" +".\Release\Timer.obj" +".\Release\blackshades.res" +] +Creating command line "link.exe @C:\DOCUME~1\BitlDev\LOCALS~1\Temp\RSP36.tmp" +

Output Window

+Linking... + + + +

Results

+blackshades_revenge.exe - 0 error(s), 0 warning(s) +
+ + diff --git a/blackshades_revenge/blackshades.rc b/blackshades_revenge/blackshades.rc new file mode 100644 index 0000000..8d63b36 --- /dev/null +++ b/blackshades_revenge/blackshades.rc @@ -0,0 +1,72 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON1 ICON DISCARDABLE "res\\bs.ico" +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/blackshades_revenge/blackshades_revenge.dsw b/blackshades_revenge/blackshades_revenge.dsw new file mode 100644 index 0000000..54ea10a --- /dev/null +++ b/blackshades_revenge/blackshades_revenge.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "blackshades"=.\blackshades.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/blackshades_revenge/blackshades_revenge.ncb b/blackshades_revenge/blackshades_revenge.ncb new file mode 100644 index 0000000000000000000000000000000000000000..c5b7f3b29ae323c63e7b7545d5527e2f15d3a1f8 GIT binary patch literal 271360 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¨|^wOyw1C>LDb) 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 literal 0 HcmV?d00001 diff --git a/blackshades_revenge/blackshades_revenge.opt b/blackshades_revenge/blackshades_revenge.opt new file mode 100644 index 0000000000000000000000000000000000000000..0d832181e904902e63da0a872e84948ed6f96067 GIT binary patch literal 51712 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 F{67Gmcp3lz literal 0 HcmV?d00001 diff --git a/blackshades_revenge/icon.tga b/blackshades_revenge/icon.tga new file mode 100644 index 0000000000000000000000000000000000000000..9f046813b198bfb898b399c10c91f48692c74873 GIT binary patch literal 6339 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 literal 0 HcmV?d00001 diff --git a/blackshades_revenge/res/bs.ico b/blackshades_revenge/res/bs.ico new file mode 100644 index 0000000000000000000000000000000000000000..91277db3697b061f498ad1ecb42610e09e8ade50 GIT binary patch literal 25214 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 literal 0 HcmV?d00001 diff --git a/blackshades_revenge/resource.h b/blackshades_revenge/resource.h new file mode 100644 index 0000000..a95e1d2 --- /dev/null +++ b/blackshades_revenge/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by qnd.rc +// +#define IDI_ICON1 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/blackshades_revenge/stderr.txt b/blackshades_revenge/stderr.txt new file mode 100644 index 0000000..f1e4151 --- /dev/null +++ b/blackshades_revenge/stderr.txt @@ -0,0 +1 @@ +STUB: C:\Documents and Settings\BitlDev\Desktop\blackshades\Source\GameInitDispose.cpp, line 3625 diff --git a/blackshades_revenge/uDevGame_License b/blackshades_revenge/uDevGame_License new file mode 100644 index 0000000..3463176 --- /dev/null +++ b/blackshades_revenge/uDevGame_License @@ -0,0 +1 @@ +UDEVGAME LICENSE Version 2, June 2001 Copyright (c) 2002, David Rosen All rights reserved. LIMITED USE SOFTWARE LICENSE AGREEMENT This Limited Use Software License Agreement (the "Agreement") is a legal agreement between you, idevgames.com, and David Rosen. By downloading or purchasing the software material, which includes source code (the "Source Code"), you are agreeing to be bound by the terms of this Agreement. If you do not agree to the terms of this Agreement, promptly destroy the Software. 1. Grant of License. Developer grants to you the right to use the Software. You have no ownership or proprietary rights in or to the Software. For purposes of this section, "use" means loading the Software into RAM, as well as installation on a hard disk or other storage device. The Software, together with any archive copy thereof, shall be destroyed when no longer used in accordance with this Agreement, or when the right to use the Software is terminated. 2. Permitted Uses. You may make any modifications to the Software and recompile the Software for your own private use. For educational purposes only, you, the end-user, may use portions of the Source Code (not to exceed 1000 lines of code), such as particular routines, to develop your own software, but may not duplicate the Source Code in its entirety. The limited right referenced in the preceding sentence is hereinafter referred to as "Educational Use." By so exercising the Educational Use right you shall not obtain any ownership, copyright, proprietary or other interest in or to the Source Code, or any portion of the Source Code. 3. Prohibited Uses. With the exception of the Educational Use right, you may not otherwise use the Software, or any portion of the Software, which includes the Source Code, for commercial gain. 4. Copyright. The Developer of this Software retains ownership rights to this Software. "idevgames.com" shall retain exclusive distribution rights to this Software. You may not otherwise reproduce, copy or disclose to others, in whole or in any part, the Software. You may not copy the written materials accompanying the Software. You agree to use your best efforts to see that any user of the Software licensed hereunder complies with this Agreement. 5. No Warranties. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. \ No newline at end of file diff --git a/blackshades_revenge/uDevGame_License.txt b/blackshades_revenge/uDevGame_License.txt new file mode 100644 index 0000000..8df83ae --- /dev/null +++ b/blackshades_revenge/uDevGame_License.txt @@ -0,0 +1,54 @@ +UDEVGAME LICENSE +Version 2, June 2001 + +Copyright (c) 2002, David Rosen All rights reserved. + +LIMITED USE SOFTWARE LICENSE AGREEMENT + +This Limited Use Software License Agreement (the "Agreement") is a legal +agreement between you, idevgames.com, and David Rosen. By downloading or +purchasing the software material, which includes source code (the "Source +Code"), you are agreeing to be bound by the terms of this Agreement. If you do +not agree to the terms of this Agreement, promptly destroy the Software. + +1. Grant of License. +Developer grants to you the right to use the Software. You have no ownership or +proprietary rights in or to the Software. For purposes of this section, "use" +means loading the Software into RAM, as well as installation on a hard disk or +other storage device. The Software, together with any archive copy thereof, +shall be destroyed when no longer used in accordance with this Agreement, or +when the right to use the Software is terminated. + +2. Permitted Uses. +You may make any modifications to the Software and recompile the Software for +your own private use. For educational purposes only, you, the end-user, may use +portions of the Source Code (not to exceed 1000 lines of code), such as +particular routines, to develop your own software, but may not duplicate the +Source Code in its entirety. The limited right referenced in the preceding +sentence is hereinafter referred to as "Educational Use." By so exercising the +Educational Use right you shall not obtain any ownership, copyright, proprietary +or other interest in or to the Source Code, or any portion of the Source Code. + +3. Prohibited Uses. +With the exception of the Educational Use right, you may not otherwise use the +Software, or any portion of the Software, which includes the Source Code, for +commercial gain. + +4. Copyright. +The Developer of this Software retains ownership rights to this Software. +"idevgames.com" shall retain exclusive distribution rights to this Software. You +may not otherwise reproduce, copy or disclose to others, in whole or in any +part, the Software. You may not copy the written materials accompanying the +Software. You agree to use your best efforts to see that any user of the +Software licensed hereunder complies with this Agreement. + +5. No Warranties. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. diff --git a/blackshades_revenge/uDevGame_Readme b/blackshades_revenge/uDevGame_Readme new file mode 100644 index 0000000..8d37361 --- /dev/null +++ b/blackshades_revenge/uDevGame_Readme @@ -0,0 +1,13 @@ +uDevGame Ñ The Macintosh Game Programming Contest + +This program was originally entered into a Macintosh game programming contest called uDevGame held by iDevGames.com. + +As per the conditions of entry into the contest, all contestants were required to provide the source code of their entries which would later be made public in accordance with their choice of a limited number of licensing arrangements. + +To see the source code for other entries or for further information on the contest which is held annually, please visit: + +http://www.idevgames.com/ + +A wide range of other Macintosh gaming source code is also made available at the site. + +Questions concerning this package should be addressed to the original developer. For further assistance, please contact: editor@idevgames.com diff --git a/images/revengeimage1.png b/images/revengeimage1.png new file mode 100644 index 0000000000000000000000000000000000000000..66c26eb3cba9fa797f8376337d0f67a1f0cafb3e GIT binary patch literal 77717 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 literal 0 HcmV?d00001